File packer.hpp¶
File List > base > packer.hpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* packer.hpp
*/
#ifndef _PACKER_HPP_
#define _PACKER_HPP_
#include "porting.h"
#include "dbtype_def.h"
#include "mem_block.hpp"
#include <functional>
#include <vector>
#include <string>
#include <utility>
// forward definition
struct or_buf;
struct db_value;
namespace cubpacking
{
class packable_object;
};
/*
* the packer object packs primitive objects from a buffer and unpacker unpacks same objects from the buffer.
* the packer & unpacker implementations should be mirrored.
*
* the buffer is provided at initialization; packer/unpacker classes are not meant for multi-threaded access.
*/
namespace cubpacking
{
class EXPORT_IMPORT packer
{
public:
packer ();
packer (char *storage, const size_t amount);
void set_buffer (char *storage, const size_t amount);
size_t get_packed_int_size (size_t curr_offset);
void pack_int (const int value);
size_t get_packed_bool_size (size_t curr_offset);
void pack_bool (const bool value);
size_t get_packed_short_size (size_t curr_offset);
void pack_short (const short value);
size_t get_packed_bigint_size (size_t curr_offset);
void pack_bigint (const std::int64_t &value);
void pack_bigint (const std::uint64_t &value);
size_t get_packed_db_value_size (const db_value &value, size_t curr_offset);
void pack_db_value (const db_value &value);
size_t get_packed_string_size (const std::string &str, const size_t curr_offset);
void pack_string (const std::string &str);
size_t get_packed_c_string_size (const char *str, const size_t str_size, const size_t curr_offset);
void pack_c_string (const char *str, const size_t str_size);
size_t get_packed_oid_size (const size_t curr_offset);
void pack_oid (const OID &oid);
// packer should gradually replace OR_BUF, but they will coexist for a while. there will be functionality
// strictly dependent on or_buf, so packer will have to cede at least some of the packing to or_buf
//
void delegate_to_or_buf (const size_t size, or_buf &buf);
const char *get_curr_ptr (void);;
size_t get_current_size (void);
void align (const size_t req_alignment);
const char *get_buffer_start (void);
const char *get_buffer_end (void);
bool is_ended (void);
std::size_t get_packed_buffer_size (const char *stream, const std::size_t length, const std::size_t curr_offset) const;
void pack_buffer_with_length (const char *stream, const std::size_t length);
// template functions to pack objects in bulk
// note - it requires versions of get_packed_size_overloaded and pack_overloaded
// get packed size of all arguments. equivalent to:
//
// size_t total_size = 0;
// for (arg : args)
// total_size += get_packed_size_overloaded (arg);
// return total_size;
//
template <typename ... Args>
size_t get_all_packed_size (Args &&... args);
template <typename ... Args>
size_t get_all_packed_size_starting_offset (size_t start_offset, Args &&... args);
// pack all arguments. equivalent to:
//
// for (arg : args)
// pack_overloaded (arg);
//
template <typename ... Args>
void pack_all (Args &&... args);
// compute size of all arguments, extend the buffer to required size and then pack all arguments
template <typename ExtBlk, typename ... Args>
void set_buffer_and_pack_all (ExtBlk &eb, Args &&... args);
// compute size of all arguments, extend the buffer by new required size
// and then pack all arguments and then end of previous end of buffer
template <typename ExtBlk, typename ... Args>
void append_to_buffer_and_pack_all (ExtBlk &eb, Args &&... args);
bool has_error (void) const;
size_t get_packed_int_array_size (size_t curr_offset, const size_t count);
void pack_int_array (const int *array, const int count);
private:
size_t get_packed_size_overloaded (const int value, size_t curr_offset);
void pack_overloaded (const int value);
size_t get_packed_size_overloaded (const bool value, size_t curr_offset);
void pack_overloaded (const bool value);
size_t get_packed_size_overloaded (const short value, size_t curr_offset);
void pack_overloaded (const short value);
size_t get_packed_size_overloaded (const std::int64_t &value, size_t curr_offset);
void pack_overloaded (const std::int64_t &value);
size_t get_packed_size_overloaded (const std::uint64_t &value, size_t curr_offset);
void pack_overloaded (const std::uint64_t &value);
size_t get_packed_size_overloaded (const db_value &value, size_t curr_offset);
void pack_overloaded (const db_value &value);
size_t get_packed_size_overloaded (const std::string &value, size_t curr_offset);
void pack_overloaded (const std::string &str);
size_t get_packed_size_overloaded (const char *value, size_t curr_offset);
void pack_overloaded (const char *str);
size_t get_packed_size_overloaded (const OID &oid, size_t curr_offset);
void pack_overloaded (const OID &oid);
size_t get_packed_size_overloaded (const packable_object &po, size_t curr_offset);
void pack_overloaded (const packable_object &po);
template <typename T>
size_t get_packed_size_overloaded (const std::reference_wrapper<T> &wrapper, const size_t curr_offset);
template <typename T>
void pack_overloaded (const std::reference_wrapper<T> &wrapper);
template <typename T>
size_t get_packed_size_overloaded (const std::vector<T> &container, const size_t curr_offset);
template <typename T>
void pack_overloaded (const std::vector<T> &container);
size_t get_packed_size_overloaded (const cubmem::block &blk, size_t curr_offset);
void pack_overloaded (const cubmem::block &blk);
void pack_small_c_string (const char *string, const size_t str_size);
void pack_large_c_string (const char *string, const size_t str_size);
template <typename T, typename ... Args>
size_t get_all_packed_size_recursive (size_t curr_offset, T &&t, Args &&... args);
template <typename T>
size_t get_all_packed_size_recursive (size_t curr_offset, T &&t);
template <typename T, typename ... Args>
void pack_all_recursive (T &&t, Args &&... args);
template <typename T>
void pack_all_recursive (T &&t);
int m_error_code;
const char *m_start_ptr; /* start of buffer */
const char *m_end_ptr; /* end of available serialization scope */
char *m_ptr;
};
class EXPORT_IMPORT unpacker
{
public:
unpacker () = default;
unpacker (const char *storage, const size_t amount);
unpacker (const cubmem::block &blk);
void set_buffer (const char *storage, const size_t amount);
void unpack_int (int &value);
void unpack_int_array (int *array, int &count);
void unpack_bool (bool &value);
void unpack_short (short &value);
void unpack_bigint (std::int64_t &value);
void unpack_bigint (std::uint64_t &value);
void unpack_string (std::string &str);
void unpack_c_string (char *str, const size_t max_str_size);
void unpack_string_to_memblock (cubmem::extensible_block &blk);
void unpack_db_value (db_value &value);
void peek_unpack_buffer_length (int &value);
void unpack_buffer_with_length (char *stream, const std::size_t max_length);
void unpack_oid (OID &oid);
const char *get_curr_ptr (void);
void align (const size_t req_alignment);
size_t get_current_size (void);
const char *get_buffer_start (void);
const char *get_buffer_end (void);
bool is_ended (void);
// packer should gradually replace OR_BUF, but they will coexist for a while. there will be functionality
// strictly dependent on or_buf, so packer will have to cede at least some of the packing to or_buf
//
void delegate_to_or_buf (const size_t size, or_buf &buf);
// template functions to unpack object in bulk
// note - it requires implementations of unpack_overloaded for all types
// unpack all arguments. equivalent to:
//
// for (arg : args)
// unpack_overloaded (arg);
//
// note - arguments should be of same type and order like when they were packed.
template <typename ... Args>
void unpack_all (Args &&... args);
bool has_error (void) const;
private:
void peek_unpack_int (int &value);
void unpack_large_string (std::string &str);
void unpack_overloaded (int &value);
void unpack_overloaded (bool &value);
void unpack_overloaded (short &value);
void unpack_overloaded (std::int64_t &value);
void unpack_overloaded (std::uint64_t &value);
void unpack_overloaded (std::string &str);
void unpack_overloaded (db_value &value);
void unpack_overloaded (packable_object &po);
void unpack_overloaded (cubmem::block &blk);
void unpack_overloaded (OID &oid);
template <typename T>
void unpack_overloaded (std::vector<T> &container);
void unpack_string_size (size_t &len);
template <typename T, typename ... Args>
void unpack_all_recursive (T &&t, Args &&... args);
template <typename T>
void unpack_all_recursive (T &&t);
int m_error_code;
const char *m_start_ptr; /* start of buffer */
const char *m_end_ptr; /* end of available serialization scope */
const char *m_ptr;
};
} // namespace cubpacking
// for legacy C files, because indent is confused by namespaces
using packing_packer = cubpacking::packer;
using packing_unpacker = cubpacking::unpacker;
// Template/inline implementation
namespace cubpacking
{
//
// packer
//
template <typename T>
void
packer::pack_overloaded (const std::reference_wrapper<T> &wrapper)
{
pack_overloaded (wrapper.get ());
}
template <typename T>
size_t
packer::get_packed_size_overloaded (const std::reference_wrapper<T> &wrapper, size_t curr_offset)
{
return get_packed_size_overloaded (wrapper.get(), curr_offset);
}
template <typename T>
size_t
packer::get_packed_size_overloaded (const std::vector<T> &container, const size_t curr_offset)
{
size_t size = get_packed_bigint_size (curr_offset);
if (size > 0)
{
for (const T &t: container)
{
size += get_packed_size_overloaded (t, size);
}
}
return size;
}
template <typename T>
void
packer::pack_overloaded (const std::vector<T> &container)
{
const size_t count = container.size ();
pack_bigint (count);
if (count > 0)
{
for (const T &t : container)
{
pack_overloaded (t);
}
}
}
template <typename ... Args>
size_t
packer::get_all_packed_size (Args &&... args)
{
return get_all_packed_size_recursive (0, std::forward<Args> (args)...);
}
template <typename ... Args>
size_t
packer::get_all_packed_size_starting_offset (size_t start_offset, Args &&... args)
{
size_t total_size = get_all_packed_size_recursive (start_offset, std::forward<Args> (args)...);
return total_size - start_offset;
}
template <typename T>
size_t
packer::get_all_packed_size_recursive (size_t curr_offset, T &&t)
{
return curr_offset + get_packed_size_overloaded (std::forward<T> (t), curr_offset);
}
template <typename T, typename ... Args>
size_t
packer::get_all_packed_size_recursive (size_t curr_offset, T &&t, Args &&... args)
{
size_t next_offset = curr_offset + get_packed_size_overloaded (std::forward<T> (t), curr_offset);
return get_all_packed_size_recursive (next_offset, std::forward<Args> (args)...);
}
template <typename ... Args>
void
packer::pack_all (Args &&... args)
{
pack_all_recursive (std::forward<Args> (args)...);
}
template <typename T>
void
packer::pack_all_recursive (T &&t)
{
pack_overloaded (std::forward<T> (t));
}
template <typename T, typename ... Args>
void
packer::pack_all_recursive (T &&t, Args &&... args)
{
pack_overloaded (std::forward<T> (t));
pack_all_recursive (std::forward<Args> (args)...);
}
template <typename ExtBlk, typename ... Args>
void
packer::set_buffer_and_pack_all (ExtBlk &eb, Args &&... args)
{
size_t total_size = get_all_packed_size (std::forward<Args> (args)...);
eb.extend_to (total_size);
set_buffer (eb.get_ptr (), total_size);
pack_all_recursive (std::forward<Args> (args)...);
}
template <typename ExtBlk, typename ... Args>
void
packer::append_to_buffer_and_pack_all (ExtBlk &eb, Args &&... args)
{
if (get_buffer_start () != eb.get_ptr ())
{
/* first call */
return set_buffer_and_pack_all (eb, std::forward<Args> (args)...);
}
assert (get_curr_ptr () >= eb.get_ptr () && get_curr_ptr () <= eb.get_ptr () + eb.get_size ());
size_t offset = get_curr_ptr () - get_buffer_start ();
assert (offset >= 0);
size_t available = eb.get_ptr () + eb.get_size () - get_curr_ptr ();
size_t total_size = get_all_packed_size (std::forward<Args> (args)...);
if (available < total_size)
{
eb.extend_by (total_size - available);
}
m_start_ptr = eb.get_ptr ();
m_ptr = eb.get_ptr () + offset;
m_end_ptr = eb.get_ptr () + offset + total_size;
pack_all_recursive (std::forward<Args> (args)...);
}
//
// unpacker
//
template <typename T>
void
unpacker::unpack_overloaded (std::vector<T> &container)
{
int64_t count;
unpack_bigint (count);
if (count > 0)
{
container.resize (count);
for (int i = 0; i < count; i++)
{
unpack_overloaded (container[i]);
}
}
}
template <typename ... Args>
void
unpacker::unpack_all (Args &&... args)
{
unpack_all_recursive (std::forward<Args> (args)...);
}
template <typename T, typename ... Args>
void
unpacker::unpack_all_recursive (T &&t, Args &&... args)
{
unpack_overloaded (std::forward<T> (t));
unpack_all_recursive (std::forward<Args> (args)...);
}
template <typename T>
void
unpacker::unpack_all_recursive (T &&t)
{
unpack_overloaded (std::forward<T> (t));
}
} // namespace cubpacking
#endif /* _PACKER_HPP_ */