C++ Boost

Serialization

extended_type_info


Motivation
Runtime Interface
Requirements
Models
Example

Motivation

The serialization library needs a system like type_info/typeid() to perform the following functions
  1. given a pointer to a type T discover the true type pointed to.
  2. given an "external" key - determine what type of object to create.

The problem with std::type_info

Features

extended_type_info is an implementation of std::type_info functionality with the following features: Exported types are maintained in a global table so that given a string key, the corresponding type can be found. This facility is used by the serialization library in order to construct types serialized through a base class pointer.

Runtime Interface


namespace boost { 
namespace serialization {

class extended_type_info
{
protected:
    // this class can't be used as is. It's just the 
    // common functionality for all type_info replacement
    // systems.  Hence, make these protected
    const char * m_key;
    extended_type_info(const unsigned int type_info_key);
    ~extended_type_info();
public:
    void key_register(const char *key);
    const char * get_key() const {
        return m_key;
    }
    bool operator<(const extended_type_info &rhs) const;
    bool operator==(const extended_type_info &rhs) const;
    bool operator!=(const extended_type_info &rhs) const {
        return !(operator==(rhs));
    }
    // for plugins
    virtual void * construct(unsigned int count = 0, ...) const;
    virtual void destroy(void const * const p) const;
    static const extended_type_info * find(const char *key);
};

} // namespace serialization 
} // namespace boost

Generally, there will be one and only one extended_type_info instance created for each type. However, this is enforced only at the executable module level. That is, if a program includes some shared libraries or DLLS, there may be more than one instance of this class correponding to a particular type. For this reason the comparison functions below can't just compare the addresses of this instance but rather must be programmed to compare the the actual information the instances contain.


extended_type_info(unsigned int type_info_key);

This constructor should be called by all derived classes. The argument should be the particular implementation. For this default implementation base on typeid(), this is the value 1. Each system must have its own integer. This value is used to permit the inter-operability of different typeinfo systems.


void key_register(const char *key);

Assign a unique character string identifier to this extended_type_info instance and add it to the corresponding global trable. This key is used to identify a type accross different instances of the program. In this way, one instance may know what type to create when necessary. For this purpose, it must be the same in all program instances which refer to the same type.

It may sometimes be referred to as a GUID - a Global Unique IDentifier.


const char *get_key() const;

Retrieves the key for extended_type_info instance. If no key has been associated with the instance, then a NULL is returned.


bool operator<(const extended_type_info & rhs) const;
bool operator==(const extended_type_info & rhs) const;
bool operator!=(const extended_type_info & rhs) const;

These functions are used to compare two extended_type_info objects. They a strict total ordering on all instances of this class.


virtual void * construct(unsigned int count = 0, ...) const;

Construct a new instance of the type to which this extended_type_info record corresponds. This function takes variable list of up to 4 arguments of any type. These arguments are passed to the type's constructor at runtime. In order to use the facility, one must declare a type sequence for the constructor arguments. Arguments for this function must match in number and type with those specified when the type was exported. This function permits one to create instances of any exported type given only the exported GUID assigned with BOOST_CLASS_EXPORT. If these types are defined in DLLS or shared libraries. When these modules are loaded at runtime, these constructor can be called until the module is unloaded. These modules are referred to as plugin.


virtual void destroy(void const * const p) const;

Destroy an instance created by the above constructor.


static const extended_type_info * find(const char *key);

Given a character string key or GUID, return the address of a corresponding extended_type_info object.

Requirements

In order to be used by the serialization library, an implementation of extended_type_info, (referred to as ETI here), must be derived from extended_type_info and also implement the following:

template<class ETI>
static extended_type_info &
ETI::get_mutable_instance();
static const extended_type_info &
ETI::get_const:instance();

Return a pointer to the instance of extended_type_info which corresponds to type T. Normally these instances are static objects so this just amounts to returning the address of this static object.

template<class ETI>
const extended_type_info *
ETI::get_derived_extended_type_info(const T & t) const;

Return a pointer to the extended_type_info instance that corresponds to the "true type" of the type T. The "true type" is the lowest type in the hierarchy of classes. The type T can always be cast to the "true type" with a static cast. Implemention of this function will vary among type id systems and sometimes will make presumptions about the type T than can be identified with a particular extended_type_info implementation.

bool ETI::less_than(const extended_type_info &rhs) const;

Compare this instance to another one using the same extended_type_info implementation.

Models

The serialization library includes two distinct extended_type_info implementations.

extended_type_info_typeid

is implemented in terms of the standard typeid(). It presumes that RTTI support is enabled by the compiler.

extended_type_info_no_rtti

is implemented in a way that doesn't rely on the existence RTTI. However, if the export facility is to be used to serialize types through base class pointers, those types are required to implement a virtual function with the signature:
virtual const char * get_key();
which returns a unique string the most derived object this class. This function must be virtual in order to implement the functionality required by ETI::get_derived_extended_type_info as described above.

Example

The test program test_no_rtti implements this function in terms of the extended_type_info API above to return the export key associated with the class. This requires that non-abstract types be exported. It also demostrates the inter-operability with between two different implementations of extended_type_info.

© Copyright Robert Ramey 2005. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)