Serialization - extended_type_info

###  | # 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`

- The main function we require - `std::typeid()` is not available in all environments. Support for this function depends upon runtime typing(RTTI) support from the compiler. This may be non-existent or not enabled for reasons such as a percieved inefficiency.
- `std::type_info` includes a string containing type name. This would seem to satisfy 2) above. But the format of this string is not consistent accross compilers, libraries, and operating systems. This makes it unusable for support of portable archives.
- Even if the type name string could somehow be made portable, there is no guarantee that class headers would be included in the same namespace accross different applications. In fact, including different headers in different namespaces is an accepted method used to avoid namespace conflicts. Thus the namespace::class_name can't be used as a key.
- There exists the possibility that different classes use different type id mechanisms. The class header might include this information. If we want to import class headers accross applications, it's convenient that the type id mechanism support inter-operability accross different type id systems.

### Features

`extended_type_info` is an implementation of `std::type_info` functionality with the following features:

- Builds a set of `extended_type_info` records - one for each type serialized.
- permits association of an arbitrary string key with a type. Often this key would be the class name - but it doesn't have to be. This key is referred to as a GUID - Globally Unique IDentifier. Presumably it should be unique in the universe. Typically this GUID would be in header files and be used to match type accross applications. The macro BOOST_CLASS_EXPORT can be invoked to associate a string key with any known type. We'll refer to these types as "exported types"
- permits the "mixing" of type info systems. For example, one class might use `typeid()` to find the external identifier of a class while another might not.

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
        extended_type_info(
            const unsigned int type_info_key,
            const char * key
        );
        ~extended_type_info();
        void key_register();
        void key_unregister();
    public:
        const char * get_key() const;
        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 actual information the instances contain.

####

    extended_type_info(unsigned int type_info_key, const char *key);

  This constructor should be called by all derived classes. The first 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.

  The second argument is a const string which is the external name of the type to which this record corresponds. It may sometimes be referred to as a GUID - a Global Unique IDentifier. It is passed through archives from one program invocation to another to uniquely identify the types that the archive contains. If the "export" facility is not going to be used, this value may be NULL.

####

    void key_register();
    void key_unregister();

  This system maintains a global table which relates external strings to `extended_type_info` records. This table is used when loading pointers to objects serialized through a base class pointer. In this case, the archive contains a string which is looked up in this table to determine which `extended_type_info` to use for creating a new object.

  These functions are called by constructors and destructors of classes which implement `extended_type_info` to add and remove entries from this table.

####

    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 `extended_type_info` objects. They impose a strict total ordering on all `extended_type_info` records.

####

    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 a 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 loaded at runtime, these constructors can be called until the module is unloaded. Such modules are referred to as plugins.

####

    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 for an Implementation

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>
    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. Implementation 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.

#### `

    virtual bool ETI::is_less_than(const extended_type_info &rhs) const;

`

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

#### `

    virtual bool ETI::is_equal(const extended_type_info &rhs) const;

`

  Compare this instance to another one using the same `extended_type_info` implementation. Return `true` if the types referred to are the same. Otherwise return `false`

#### `

    const char ETI::get_key() const;

`

  Retrieve the external key (aka GUID) for this class.

#### `

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

`

  Construct an instance of the corresponding type with the include argument list.

#### `

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

`

  Destroy an instance of this type. This calls the proper destructor and recovers allocated memory.

### 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. Instead, it requires that all polymorphic types be explictly exported. In addition, 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 demonstrates the inter-operability between two different implementations of `extended_type_info`.

### Requirements for Each Type

Each type to be managed by the system must be "registered" individually. This is accomplished by instantiating templates. For example, if the type T is to use the type_info system one would include the following code: `

    namespace boost {
    namespace serialization {
    template
    struct extended_type_info_typeid>T>;
    template
    struct extended_type_info_typeid>const T>;
    } // serialization
    } // boost

` For those using the serialization library, this step can be skipped as it is done automatically. The serialization library includes the macro: `

    BOOST_CLASS_TYPE_INFO(
        my_type,
        extended_type_info_typeid>my_class>
    )

` which is used to specify which `extended_type_info` system is to be used for a given type.

`extended_type_info` includes a facility for constructing instances of types without knowing what the exact types are. This is done with the function `virtual void * extended_type_info::construct(unsigned int count = 0, ...) const;` . For example:
``

    struct base {
    ...
    };
    struct derived : public base {
    ...
    };
    ...
    extended_type_info *eti = extended_type_info::find("my_class")
    base * b = eti->construct(...);

The `construct` takes an argument count and up to four parameters of any type. The arguments are passed to the constructor of "my_class". A complete example of this can be found here

© Copyright Robert Ramey 2005-2009. 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)