Persistence of Basic Types


This page describes the persistence of the basic types such as integers and C-style strings (char*). The source code is split up into separate headers for each class of basic types. Each header can either be included separately or all of the headers can be included in one go by including persistent_basic.hpp.

Header persistent_basic.hpp

You can include all of the functions in one go by including persistent_basic.hpp. If you prefer however, you can include the separate headers for each class being used. The latter approach minimises the number of headers that get included indirectly.

Persistence of bool

The bool type is dumped and restored as a small unsigned integer. The format is platform-independent.

void stlplus::dump_bool(dump_context&, const bool& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_bool(restore_context&, bool& data) throw(stlplus::persistent_restore_failed);

Persistence of Integer Types

A separate function is defined for each of the built-in integer types in C++. This leads to the following family of functions:

void stlplus::dump_char(dump_context&, const char& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_char(restore_context&, char& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_signed_char(dump_context&, const signed char& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_signed_char(restore_context&, signed char& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_unsigned_char(dump_context&, const unsigned char& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_unsigned_char(restore_context&, unsigned char& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_short(dump_context&, const short& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_short(restore_context&, short& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_unsigned_short(dump_context&, const unsigned short& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_unsigned_short(restore_context&, unsigned short& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_int(dump_context&, const int& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_int(restore_context&, int& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_unsigned(dump_context&, const unsigned& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_unsigned(restore_context&, unsigned& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_long(dump_context&, const long& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_long(restore_context&, long& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_unsigned_long(dump_context&, const unsigned long& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_unsigned_long(restore_context&, unsigned long& data) throw(stlplus::persistent_restore_failed);

It is important to use the right dump or restore function for the type being saved.

The underlying format is platform-independent, although it is different for signed and unsigned types. Issues such as different word lengths on different CPUs are handled correctly internally. For example, on some CPUs, the long type is 32-bits, whilst on others it is 64-bits. A data structure dumped with 32-bit longs will be correctly restored on a CPU with 64-bit longs. The only potential problem is when you dump a 64-bit long and restore to a 32-bit long. If (and only if) the value is too big to store in 32 bits, the restore function will throw an stlplus::persistent_restore_failed exception. It is your responsibility to use types that will store the possible values on all platforms you are porting to.

Persistence of Enumeration Types

Enumeration types are essentially small integers. However, each type is considered to be a different type by the compiler - so therefore they cannot actually be treated as simple integer types - you get a compilation error. The solution that I supply is a pair of template functions that adapt themselves to the type of the enum being made persistent. The functions are:

template<typename T>
void stlplus::dump_enum(dump_context&, const T& data) throw(stlplus::persistent_dump_failed);

template<typename T>
void stlplus::restore_enum(restore_context&, T& data) throw(stlplus::persistent_restore_failed);

Consider the following example. The enum defines a traffic light sequence:

enum traffic_lights {red, red_amber, green, amber};

This can be used with dump_enum and restore_enum directly, but is is better style to write dump and restore functions that call the template functions, thus hiding the use of the template:

#include "persistent_contexts.hpp"
#include "persistent_enum.hpp"

void dump_traffic_lights(stlplus::dump_context& context, const traffic_lights& lights)
  stlplus::dump_enum(context, lights);

void restore_traffic_lights(stlplus::restore_context& context, traffic_lights& lights)
  stlplus::restore_enum(context, lights);

Persistence of Floating-Point Types

Persistence of floating-point types is supported but with a warning: this is the one basic type for which I have not been able to find a completely portable representation. Thus there may be platform-specific problems with the format. If this is a problem for your application, then convert to a string representation and dump the string. However, the binary routines presented here are far more efficient and are provided for those cases where there are no portability problems and where performance is an issue.

void stlplus::dump_float(dump_context&, const float& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_float(restore_context&, float& data) throw(stlplus::persistent_restore_failed);

void stlplus::dump_double(dump_context&, const double& data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_double(restore_context&, double& data) throw(stlplus::persistent_restore_failed);

Persistence of C-Style Strings (char*)

Usually, pointers are treated specially by the persistence functions - see the page for persistent pointers for an explanation. The one exception is char* which is treated as a null terminated array and not a pointer to a single char. Multiple pointers to the same char* string will be dumped once and the same magic key method used as for pointers to other pointer types.

Warning! This means that pointers to char cannot be supported, since there is no type difference between a pointer to char and a C-style array of char.

void stlplus::dump_cstring(dump_context&, const char* data) throw(stlplus::persistent_dump_failed);
void stlplus::restore_cstring(restore_context&, char*& data) throw(stlplus::persistent_restore_failed);

Warning! The restore deletes any old value of the data parameter and allocates a new char* which is (just) big enough and assigns it to the data field. This is because there is no way of knowing how long a char* is so the passed parameter is not safe to use. The allocation is done using standard new. If the data field is non-null on entry it will be deleted by standard delete. Best to make it null in the first place.

#include "persistent_contexts.hpp"
#include "persistent_cstring.hpp"


char* data = 0;
stlplus::restore_cstring(context, data);