# The State Library

The state library provides means for objects to save and restore their state.

Features include:

- Pointers to base types can be saved and restored. The exact types of the saved and restored objects will match.
- If the pointer to an object is saved twice, only one copy of the object is saved. When these two pointers are restored they will point to the same object.
- Virtual base classes are dealt with in a manner consistent with the way C++ treats virtual base classes.
- The library is portable. Information about object layout for particular compiler implementations is not needed.

For objects of a class to be savable with this library the class must inherit SavableState which in turn inherits DescribedClass. SavableState must be inherited with the virtual qualifier. Also, a constructor taking a StateIn& argument and a save_data_state(StateOut&) member must be provided. If the class has virtual base classes other than SavableState, then a save_vbase_state(StateOut&) member must also be provided.

- Simple Example
- Example with Inheritance
- Example with Virtual and Nonvirtual Inheritance
- Example with Pointers to SavableStates
- Example with Smart Pointers to SavableStates
- Example with Pointers to Data

## Simple Example

Here is a simple example of the specification of a client, C, of SavableState:

    class C: virtual public SavableState {
      private:
        int i;
      public:
        C(StateIn&);
        void save_data_state(StateOut&);
    };

Here is the implementation for the above:

    static ClassDesc C_cd(typeid(C),"C",1,"virtual public SavableState",
                          0, 0, create<C>);
    void C::save_data_state(StateOut&so) {
      so.put(i);
    }
    C::C(StateIn&si): SavableState(si) {
      si.get(i);
    }

## Example with Inheritance

Here is an example of the specification of C, where C nonvirtually inherits from another SavableState derivative:

    class C: public B {
      private:
        int i;
      public:
        C(StateIn&);
        void save_data_state(StateOut&);
    };

Here is the implementation for the above:

    static ClassDesc C_cd(typeid(C),"C",1,"public B",
                          0, 0, create<C>);
    void C::save_data_state(StateOut&so) {
      B::save_data_state(so);
      so.put(i);
    }
    C::C(StateIn&si): SavableState(si), B(si)  {
      si.get(i);
    }

Note that B (or one of its parents) virtually inherits from SavableState, so the StateIn constructor for SavableState is called explicitly from the class C constructor.

## Example with Virtual and Nonvirtual Inheritance

Here is an example of the specification of C, where C nonvirtually inherits from another client of SavableState as well as virtually inherits from a client of SavableState:

    class C: public B,
             virtual public E {
      private:
        int i;
      public:
        C(StateIn&);
        void save_vbase_state(StateOut&);
        void save_data_state(StateOut&);
      };

In this case a save_vbase_state member is required since virtual base classes besides SavableState exist. This member function must save the virtual base classes in the same order that virtual base classes are initialized in constructors. Virtual base classes are initialized before all other base classes in a depth first, left to right transversal of the directed acyclic graph of parent classes. In this example, B and E inherit virtually from SavableState. Here is the implementation:

    static ClassDesc C_cd(typeid(C),"C",1,"public B, virtual public E",
                          0, 0, create<C>);
    void C::save_vbase_state(StateOut&sio) {
      SavableState::save_data_state(so);
      E::save_data_state(sio);
    }
    void C::save_data_state(StateOut&so) {
      B::save_parent_state(so);
      so.put(i);
    }
    C::C(StateIn&si): SavableState(si), B(si), E(si) {
      si.get(i);
    }

## Example with Pointers to SavableStates

Here is an example where C has data members which are pointers to derivatives of SavableState:

    class C: virtual public SavableState {
      private:
        A* ap; // A is also a SavableState
      public:
        C(StateIn&);
        void save_data_state(StateOut&);
      };

Here is the implementation for the above:

    static ClassDesc C_cd(typeid(C),"C",1,"virtual public SavableState",
                          0, 0, create<C>);
    void C::save_data_state(StateOut&so) {
      SavableState::save_state(ap,so);
    }
    C::C(StateIn&si): SavableState(si) {
      ap = dynamic_cast(SavableState::restore_state(si));
    }

## Example with Smart Pointers to SavableStates

Here is an example where C has data members which are smart pointers to derivatives of SavableState:

    class C: virtual public SavableState {
      private:
        Ref a; // A is also a SavableState
      public:
        C(StateIn&);
        void save_data_state(StateOut&);
    };

Here is the implementation for the above:

    static ClassDesc C_cd(typeid(C),"C",1,"virtual public SavableState",
                          0, 0, create<C>);
    void C::save_data_state(StateOut&so) {
      SavableState::save_state(a.pointer(),so);
    }
    C::C(StateIn&si): SavableState(si) {
      a << SavableState::restore_state(so);
    }

## Example with Pointers to Data

Here is an example where C has data members which are pointers to data:

    class C: virtual public SavableState {
      private:
        int vecsize;
        double *vec;
        int n1;
        int n2;
        double **array;
      public:
        C(StateIn&);
        void save_data_state(StateOut&);
    };

Here is the implementation for the above:

    static ClassDesc C_cd(typeid(C),"C",1,"virtual public SavableState",
                          0, 0, create<C>);
    void C::save_data_state(StateOut&so) {
      so.put(vecsize);
      so.put_array_double(vec,vecsize);

      so.put(n1);
      so.put(n2);
      for (int i=0; i<n1; i++) {
        so.put_array_double(array[i],n2);
      }
    }
    C::C(StateIn&si): SavableState(si) {
      si.get(vecsize);
      vec = new double[vecsize];
      si.get_array_double(vec,vecsize);

      si.get(n1);
      si.get(n2);

      array = new double*[n1];
      for (int i=0; i<n1; i++) {
        array[i] = new double[n2];
        si.get_array_double(array[i],n2);
      }
    }