|
constexpr | typer (const pass_type p) noexcept |
| Creates a new typer. More...
|
|
template<typename T > |
| typer (T &dest, T const &src, void *base, const std::size_t offset) |
| Creates a new typer for packing an object. More...
|
|
| typer (void *base) |
| Creates a new typer for unpacking an object. More...
|
|
| typer (typer const &)=delete |
|
typer & | operator= (typer const &)=delete |
|
pass_type | pass (void) noexcept |
| Returns the current pass of the typer. More...
|
|
std::size_t | offset (void) const noexcept |
| Returns the number of bytes since the start of the current operation.
|
|
std::pair< bool, std::size_t > | meets_requirements (void) const noexcept |
| Returns if the object meets the requested requirements.
|
|
template<typename Base > |
void | base (typename base_type_wrapper< Base >::type &t) |
| Processes a base class.
|
|
template<typename T > |
void | member (T &t) |
| Processes member t .
|
|
template<typename T > |
void | member (T const &t) |
| Processes member t . More...
|
|
template<typename T > |
void | member (T volatile &t) |
| Processes member t . More...
|
|
template<typename T > |
void | member (T const volatile &t) |
| Processes member t . More...
|
|
template<typename T > |
void | member (T &t, const std::size_t N) |
| Processes member t with an additional integral type passed to the packing functions.
|
|
template<typename T > |
void | member (T const &t, const std::size_t N) |
| Processes member t with an additional integral type passed to the packing functions. More...
|
|
template<typename T > |
void | member (T volatile &t, const std::size_t N) |
| Processes member t with an additional integral type passed to the packing functions. More...
|
|
template<typename T > |
void | member (T const volatile &t, const std::size_t N) |
| Processes member t with an additional integral type passed to the packing functions. More...
|
|
template<typename T > |
void | transient (T &t) |
| Default constructs t at unpacking.
|
|
template<typename T > |
void | transient (T const &t) |
| Default constructs t at unpacking. More...
|
|
template<typename T > |
void | transient (T volatile &t) |
| Default constructs t at unpacking. More...
|
|
template<typename T > |
void | transient (T const volatile &t) |
| Default constructs t at unpacking. More...
|
|
template<typename T , typename U > |
void | transient (T &t, U &&u) |
| Constructs t using u at unpacking.
|
|
template<typename T , typename U > |
void | transient (T const &t, U &&u) |
|
template<typename T , typename U > |
void | transient (T volatile &t, U &&u) |
|
template<typename T , typename U > |
void | transient (T const volatile &t, U &&u) |
|
template<typename T , typename U > |
void | pointer_to_member (T *&t, U *ref, const std::size_t offset=0) noexcept |
| Processes a pointer t to other member ref at offset offset .
|
|
template<typename T , typename U > |
void | pointer_to_member (T *const &t, U *ref, const std::size_t offset=0) noexcept |
| Processes a pointer t to other member ref at offset offset . More...
|
|
template<typename T , typename U > |
void | pointer_to_member (T *volatile &t, U *ref, const std::size_t offset=0) noexcept |
| Processes a pointer t to other member ref at offset offset . More...
|
|
template<typename T , typename U > |
void | pointer_to_member (T *const volatile &t, U *ref, const std::size_t offset=0) noexcept |
| Processes a pointer t to other member ref at offset offset . More...
|
|
typer class is used for packing, unpacking and copying objects.
It operates on user-defined class T
via its T::define_type()
function, which must clearly define its members to ensure proper packing/unpacking.
The body of define_type has four sections:
Section 1 is for packing any base classes of T
. It is undefined behavior to not pack the base classes before everything else.
Section 2 is for performing preliminary calculations and storing temporary values that may be necessary in sections 2 or 3 (e.g., offsets, sizes, etc). This is necessary because section 2 may modify the contents of members during packing/unpacking.
Section 3 is for defining data members: variables that store data, either automatically or via dynamic memory allocation. Section 3 starts with the first call to typer::member(). Upon packing of the object, each data member will be properly packed. If a data member is a user-defined object, it will be recursively packed.
Section 4 is for defining offset members: pointers used as points of reference within the data members previously defined in section 2 (e.g., some implementations of std::vector
store a dynamic array of data, along with an offset pointer referencing one past the array's end). Section 4 starts with the first call to typer::pointer_to_member(). Only the relative address within the type is packaged upon packing, not the object pointed to, since that object was already packed in Section 3. Attempting to define an offset member to an object not packed in Section 3 is undefined behavior.
It is recommended that members are processed in the T::define_type()
in the order they are declared in the class, although this is not necessary for correctness.
- Warning
- STL iterators are not directly supported by the primitives for packing/unpacking. They typically come in pairs, one for the beginning and one for the end of a sequence, so they cannot be packed in one pass. This can be overcome by using wrapper classes that explicitly implement a
define_type()
method that does provide the necessary information. For example, the iterators can both be stored in a class as a range with the necessary define_type()
function.
-
If two data members both contain pointers to the same object, that object will be packed twice and after unpacking you will end up with two objects. In some cases, such shared pointers are necessary for the structure of the aggregate object and using offset pointers may still allow for a valid
define_type()
. For example, each node in a doubly-linked list has two pointers, allowing for forward and backward traversals through the list. Defining both pointers to be members is not valid. The correct define_type()
will define the next pointer to be member, to recursively define the list, and the previous pointer to be a pointer to member, to correctly link the list.
-
Some implementations use
define_type()
to pack a class into contiguous memory. This packing may use memcpy()
, or other low-level mechanisms unaware of C++ classes. The C++ Standard states that only PODs may be safely memcpy'ed. However, the purpose of define_type()
is to give the typer enough information to still safely use memcpy
. As such, one should not rely on the copy constructor being invoked during its packing/unpacking.
- Example:
- A user-defined struct for holding data, demonstrating local members.
struct simple
{
int a;
double b;
{
}
};
- Example:
- A user-defined array class, demonstrating dynamic members and pointers to members.
struct array
{
array(const std::size_t size)
: begin(new int[size]), end(begin + size)
{ }
~array()
{
const std::ptrdiff_t size = end -
begin;
}
};
- Example:
- A user-defined inherited class, demonstrating how to pack a base class.
struct derived
: public simple
{
char c[10];
{
}
};