1 /*  _________________________________________________________________________
2  *
3  *  UTILIB: A utility library for developing portable C++ codes.
4  *  Copyright (c) 2008 Sandia Corporation.
5  *  This software is distributed under the BSD License.
6  *  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7  *  the U.S. Government retains certain rights in this software.
8  *  For more information, see the README file in the top UTILIB directory.
9  *  _________________________________________________________________________
10  */
11 
12 /**
13  * \file Serialize.h
14  *
15  * Defines:
16  *    - utilib::SerialObject struct
17  *    - utilib::SerialPOD class
18  *    - utilib::Serialization_Manager class
19  *    - utilib::Serializer() singleton
20  *
21  */
22 
23 #ifndef utilib_Serialize_h
24 #define utilib_Serialize_h
25 
26 #include <utilib/Any.h>
27 
28 namespace utilib {
29 
30 class Serialization_Manager;
31 
32 namespace error {
33 namespace Serialization {
34   const int EmptyData                = -300;
35   const int ExtraData                = -301;
36   const int UnknownType              = -302;
37   const int DuplicateRegistration    = -303;
38   const int BadPODData               = -304;
39   const int BadPODTextConversion     = -305;
40   const int MissingStringQuote       = -306;
41   const int UnconvertedPODText       = -307;
42 } // namespace utilib::error::Serialization
43 } // namespace utilib::error
44 
45 
46 /// Return the system-wide Serialization_Manager singleton.
47 Serialization_Manager& Serializer();
48 
49 /// Generic serializer exception from which all other exceptions will inherit
50 class serialization_error : public std::runtime_error
51 {
52 public:
53    /// Constructor
serialization_error(const std::string & msg)54    serialization_error(const std::string& msg)
55       : runtime_error(msg)
56    {}
57 };
58 
59 
60 class serializer_unknown_type : public serialization_error
61 {
62 public:
63    /// Constructor
serializer_unknown_type(const std::string & msg)64    serializer_unknown_type(const std::string& msg)
65       : serialization_error(msg)
66    {}
67 };
68 
69 class serializer_bad_pod_size : public serialization_error
70 {
71 public:
72    /// Constructor
serializer_bad_pod_size(const std::string & msg)73    serializer_bad_pod_size(const std::string& msg)
74       : serialization_error(msg)
75    {}
76 };
77 
78 
79 /// A data "pseudo-object" for containing serialized Plain-ol-Data types
80 class SerialPOD
81 {
82 public:
SerialPOD()83    SerialPOD()
84       : buffer(),
85         text_mode(false)
86    {}
SerialPOD(size_t init_size)87    SerialPOD(size_t init_size)
88       : buffer(init_size),
89         text_mode(false)
90    {}
91 
92    /// Set the contents of this SerialPOD (binary mode)
93    void set(const void* buffer_src, const size_t length);
94 
95    /// Set the contents of this SerialPOD (text mode)
96    void set(const std::string& buffer_src);
97 
98    /// Set the contents of this SerialPOD (text mode)
is_text_mode()99    bool is_text_mode() const
100    { return text_mode; }
101 
102    /// Print out the stream of character values for this SerialPOD
103    void print(std::ostream& os, std::string indent = "") const;
104 
size()105    size_t size() const
106       { return buffer.size(); }
data()107    const char* data() const
108       { return &buffer[0]; }
109 
110 private:
111    std::vector<char>  buffer;
112    bool  text_mode;
113 };
114 
115 
116 /// A structural "pseudo-object" for representing a class / structure
117 class SerialObject
118 {
119 public:
SerialObject()120    SerialObject()
121       : type(0),
122         data()
123    {}
SerialObject(size_t type_id)124    SerialObject(size_t type_id)
125       : type(type_id),
126         data()
127    {}
128 
129    void print(std::ostream& os, std::string indent = "") const;
130 
131    /// A list of SerialObjects (each element is a serialized object member)
132    typedef std::list<SerialObject> elementList_t;
133 
134    size_t  type;
135    Any     data;
136 };
137 
138 
139 
140 /// The prototype for serilization/deserialization transformation functions
141 typedef int(*transform_fcn)(SerialObject::elementList_t&, Any&, bool);
142 /// The prototype for POD serialization/deserialization functions
143 typedef int(*pod_transform_fcn)(SerialPOD&, Any&, bool);
144 /// The prototype for serialization/deserialization POD-to-text functions
145 typedef int(*pod_text_transform_fcn)(std::string&, Any&, bool);
146 /// The prototype for an instantiation function (populate the provided Any)
147 typedef void(*initialization_fcn)(Any&);
148 
149 
150 /// Class for storing and managing all serialization functions
151 /** This class stores all serialization and type initialization function
152  *  pointers and coordinates the process of serializing and
153  *  deserializing data types.  It is published to the outside world
154  *  through the Serializer() singleton.
155  *
156  *  The power of the utilib::Serialization_Manager and the
157  *  characteristic that distinguishes it from other serialization
158  *  approaches is its compatibility with the utilib::Any variant data
159  *  type.  Most serialization approaches directly leverage templates to
160  *  have the compiler insert the correct serialization / deserialization
161  *  functions at compile time.  While this works well for concrete types
162  *  (and even templated concrete types), it is incompatible with the
163  *  utilib::Any variant data type, as the compiler cannot know what data
164  *  is contained within the Any at compile time.  To facilitate the
165  *  serialization of Anys the Serialization_Manager uses a registration
166  *  system where serializable classes register their serialization
167  *  functions with the manager, allowing the manager to dynamically
168  *  locate and bind to the correct serialization function at runtime.
169  *
170  *  \par Interacting with the Serialization_Manager
171  *
172  *  Apart from registering new user-defined serializers (with
173  *  Serialization_Manager::register_serializer()), the general public
174  *  should never directly call the Serialization_Manager member
175  *  functions.  Instead, the general public should make use of the
176  *  utilib namespace-level functions:
177  *     - ::Serialize
178  *     - ::Deserialize
179  *     - ::serial_transform
180  *
181  *  In general, "users" of the serialization system will call
182  *  Serialize() and Deserialize().  As expected, Serialize() takes any
183  *  object and returns the corresponding SerialObject, and Deserialize()
184  *  takes a SerialObject and returns the deserialized object within an
185  *  Any.  In essence, Serialize() and Deserialize() are convenience
186  *  wrappers around serial_transform()
187  *
188  *  serial_transform() is a utility function to assist developers in
189  *  extending serialization capabilities by defining and registering new
190  *  serializer functions for user-defined types.  It is a wrapper around
191  *  Serialization_Manager::transform_impl() that provides a mechanism
192  *  for guaranteeing that serializers for template class instantiations
193  *  are registered \em before they are encountered during a
194  *  serialization operation.  This is covered in more detail in the
195  *  "Registering your serialization functions" section below.
196  *
197  *  \par Serialization Functions
198  *
199  *  There are three fundamental serialization functions supported by the
200  *  Serialization_Manager.  The first (::pod_transform_fcn) is for
201  *  serializing and deserializing "Plain 'ol Data" (POD) types.  It will
202  *  take the variable and convert it to/from a SerialPOD object by
203  *  storing the variable's binary data as a char vector.  The
204  *  Serialization_Manager defines and registers serializers for all
205  *  non-pointer standard C++ POD data types.
206  *
207  *  The second serialization function (::transform_fcn) is for
208  *  serializing user-defined objects.  This function converts the
209  *  contents the object in question into a SerialObject list, usually by
210  *  successively calling serial_transform().  For example, consider the
211  *  following user-defined class fragment and its (valid) serializer:
212  *
213  *  The third serialization function (::pod_text_transform_fcn) is not
214  *  necessarily part of the core Serialization_Manager functionality,
215  *  but is maintained here to assist some writers and parsers for
216  *  serialized objects.  This serialization function converts POD data
217  *  types to and from a char-based (not wchar_t-based) std::string.  The
218  *  Serialization Manager will automatically fall back to the normal
219  *  (binary) transformation if the text serialization function is NULL
220  *  (or not provided).  All standard C++ POD types provide valid text
221  *  serialization functions, with the exception of wchar_t.
222  *
223  *  \code
224  *  class A
225  *  {
226  *     // ...
227  *  private:
228  *     static int serializer( utilib::SerialObject::elementList_t & serial,
229  *                            utilib::Any & data, bool serialize )
230  *     {
231  *        A& me = const_cast<A&>(data.expose<A>());
232  *        serial_transform(serial, me.a, serialize);
233  *        serial_transform(serial, me.b, serialize);
234  *        serial_transform(serial, me.c, serialize);
235  *        return 0;
236  *     }
237  *
238  *     int a;
239  *     float b;
240  *     std::list<double> c;
241  *
242  *     static const volatile int serializer_registered;
243  *  };
244  *  \endcode  That's it!
245  *
246  *  Both ::pod_transform_fcn and ::transform_fcn serialization functions
247  *  are registered by calling one of four overloaded
248  *  Serializer().register_serializer() template functions.
249  *  register_serializer() takes a "user-defined" name, the transform
250  *  function, and an optional initialization function that returns a new
251  *  valid instance of the class within an Any (::initialization_fcn).
252  *  If not provided, ::initialization_fcn defaults to using the Default
253  *  Constructor.
254  *
255  *  \par Registering your serialization functions
256  *
257  *  In general, registering a serialization function entails notifying
258  *  the Serialization_Manager of a relationship between a \c typeid, a
259  *  user-defined name, a serialization function, and optionally, a
260  *  constructor.  For more information on creating user-defined type
261  *  names, see the section "Providing a user-defined name" below.
262  *
263  *  Proper registration of a class serialization function with the
264  *  global Serializer() singleton is the critical step in getting the
265  *  serialization process working correctly.  One of the most important
266  *  aspects is to perform all registrations as \em early in the program
267  *  executaion as possible.  Unlike template-based serialization
268  *  strategies, it is possible to DEserialize an object of a particular
269  *  class \em before that class is ever actually used in the program.
270  *  As a result,the preferable way to register a serializer is through
271  *  static variable initialization \em before entry into \c main().
272  *  While there are many nuances to the process (most revolving around
273  *  the C++ compiler and linker), most situations should fall into one
274  *  of 4 basic categories:
275  *
276  *  \par 1) A concrete class you control
277  *
278  *  This is probably the most straightforward situation.  You have a
279  *  concrete class that you have control over.  In this case, the
280  *  simplest and most robust approach is to intrusively hook your class
281  *  to the utilib::Serializer().  As in the <tt>class A</tt> example
282  *  above, make the serialization function a private static member of
283  *  the class, and add a <tt>private static const volatile int</tt>.  In
284  *  the corresponding code (\c .cpp) file, register the serialization
285  *  function by initializing the static const:
286  *
287  *  \code
288  *  const volatile int A::serializer_registered
289  *     = utilib::Serializer().register_serializer<A>("A", A::serializer);
290  *  \endcode
291 
292  *  By tying the registration to the initialization of a static
293  *  variable, simply using the class \em somewhere in the program will
294  *  cause the serializer to be registered \em before entry into \c
295  *  main().  Note, as no arguments depend on the template parameter (the
296  *  type being serialized), you must explicitly specify it when invoking
297  *  register_serializer().  Also note the use of the "volatile" keyword.
298  *  This helps prevent linkers from "optimizing away" what is otherwise
299  *  effectively a no-op.
300  *
301  *  \par 2) A template class you control
302  *
303  *  Templates are slightly more complicated than concrete classes, as
304  *  most compilers only emit template code that is actuallr \em
305  *  references somewhere in the program executable.  The solution is to
306  *  explicitly reference the static registration variable in \b all
307  *  constructors (including any copy constructors):
308  *
309  *  \code
310  *  template<typename T1, typename T2>
311  *  class B
312  *  {
313  *  public:
314  *     B() { static_cast<void>(serializer_registered); }
315  *
316  *     B(const B& rhs)
317  *     {
318  *        static_cast<void>(serializer_registered);
319  *        // ...
320  *     }
321  *
322  *  private:
323  *     static int serializer( utilib::SerialObject::elementList_t & serial,
324  *                            utilib::Any & data, bool serialize )
325  *     {
326  *        B& me = const_cast<B&>(data.expose<B>());
327  *        serial_transform(serial, me.a, serialize);
328  *        serial_transform(serial, me.b, serialize);
329  *        serial_transform(serial, me.c, serialize);
330  *        return 0;
331  *     }
332  *
333  *     T1 a;
334  *     T2 b;
335  *     std::list<T1> c;
336  *
337  *     static const volatile int serializer_registered;
338  *  };
339  *
340  *  template<typename T1, typename T2>
341  *  const volatile int A<T1,T2>::serializer_registered
342  *     = utilib::Serializer().register_serializer<A<T1,T2> >
343  *        ( std::string("B;") + utilib::mangledName(typeid(T1)) + ";"
344  *            + utilib::mangledName(typeid(T2)),
345             B<T1,T2>::serializer );
346  *  \endcode
347  *
348  *  In this case, the static const is initialized through a templated
349  *  initializer, and the \c static_cast<void>(serializer_registered)
350  *  lines create explicit references to cause the compiler to emit,
351  *  link, and register the serialization function for every
352  *  instantiation of the template class.  Note again that the use of the
353  *  \c volatile keyword is critical in this scenario.
354  *
355  *  \par 3) A concrete class that you do \em not control
356  *
357  *  This case is a relatively trivial extension of case (1).  In this
358  *  case, the class is owned or controled by someone else, so we cannot
359  *  directly edit the class API.  Given a class \c C, construct a
360  *  standalone serialization function and register it through a local
361  *  static variable:
362  *
363  *  \code
364  *  class C; // defined elsewhere
365  *
366  *  namespace {
367  *     int serialize_C( utilib::SerialObject::elementList_t & serial,
368  *                      utilib::Any & data, bool serialize )
369  *     {
370  *        C& me = const_cast<C&>(data.expose<C>());
371  *        // ... (de)serialize through C's public API ...
372  *        return 0;
373  *     }
374  *
375  *     const int c_registered
376  *        = utilib::Serializer().register_serializer<C>("C", serialize_C);
377  *  } // namespace (local)
378  *  \endcode
379  *
380  *  Note that this entire code fragment appears in a \em source (and not
381  *  header) file.  The one "gotcha" is that if this registration is
382  *  being done as part of a static library (i.e. \c *.a), it will only
383  *  be picked up by the linker if something directly referenced by \c
384  *  main() in turn references something in the source in which you
385  *  placed the registration code.
386  *
387  *  \par 4) A template class that you do \em not control
388  *
389  *  Serializing template classes controlled by others are perhaps the
390  *  most complicated example.  While individual serializations for
391  *  specific template instantiations may be handled as in case (3), the
392  *  general case that provides serialization for \em any instantiation
393  *  of the template is more involved.  A prime example of this is the
394  *  STL, for which we provide general serialization support at the
395  *  bottom of this file.  In this case, the general pattern is to make
396  *  use of the serial_transform template family.  In a header (included
397  *  before any and all places where the template class is serialized),
398  *  create the following:
399  *
400  *  \code
401  *  // Given (defined elsewhere):
402  *  template<typename T2, typename T2> class D;
403  *
404  *  template<typename T1, typename T2>
405  *  int serialize_D( utilib::SerialObject::elementList_t & serial,
406  *                   utilib::Any & data, bool serialize )
407  *  {
408  *     D& me = const_cast<D&>(data.expose<D>());
409  *     // ... (de)serialize through D's public API ...
410  *     return 0;
411  *  }
412  *
413  *  template<typename T1, typename T2>
414  *  struct D_registrar {
415  *     static const volatile int registered;
416  *  };
417  *  template<typename T1, typename T2>
418  *  const volatile int D_registrar<T1,T2>::registered
419  *     = Serializer().register_serializer< D<T1,T2> >
420  *     ( std::string("D;") + mangledName(typeid(T1)) + ";"
421  *       + mangledName(typeid(T2)), serialize_D<T1,T2> );
422  *
423  *  namespace utilib {
424  *     template<typename T1, typename T2>
425  *     int serial_transform( SerialObject::elementList_t& serial,
426  *                           D<T1,T2>& data,  bool serialize )
427  *     {
428  *        (void)&D_registrar<T1,T2>::registered;
429  *        AnyFixedRef tmp = data;
430  *        return Serializer().transform_impl( typeid(data), serial,
431  *                                            tmp, serialize );
432  *     }
433  *  } // namespace (local)
434  *  \endcode
435  *
436  *  Note that unlike cases (1) and (2), where simply \em using the class
437  *  somewhere in your program will cause the serialization function to
438  *  be automatically registered with the Serializer(), in this case, the
439  *  serializer will only be registered is the class is directly or
440  *  indirectly explicitly serialized somewhere in the program.  Indirect
441  *  references include other classes that serialize the class in
442  *  question as part of \em their serializer.  For example, \c
443  *  std::list<double> is indirectly referenced by the serializer for \c
444  *  A above, and serializing \c std::map<int,std::list<int>> will
445  *  automatically register the \c std::list<int> serializer.
446  *
447  *  If it is necessary to \em guarantee that a particular template
448  *  instantiation is registered, simply reference it in a source file,
449  *  as was done in case (3):
450  *
451  *  \code
452  *  namespace {
453  *     const int force_registration_1 = D_registrar<T1,T2>::registered;
454  *  } // namespace (local)
455  *  \endcode
456  *
457  *  \par Using the Serializer() before \c main()
458  *
459  *  As with all computations that occur before entry into \c main(),
460  *  particular care must be taken to make sure that static data is not
461  *  referenced before it is initialized.  As a general rule, <b><i>the
462  *  Serializer() should not be used before entry into main()</i></b>.
463  *  If it is absolutely necessary, there are two approaches that may
464  *  work, although both rely on creating (and including)
465  *  serial_transform() definitions for <b>\em all</b> classes that will be
466  *  serialized.  The first approach is to construct the
467  *  serial_transform() template similar to case (4):
468  *
469  *  \code
470  *  template<typename T1, typename T2>
471  *  struct D_registrar {
472  *     static const volatile int registered;
473  *     const int _register() {
474  *        return Serializer().register_serializer<D<T1,T2> >
475  *           ( std::string("D;") + mangledName(typeid(T1)) + ";"
476  *             + mangledName(typeid(T2)), serialize_D<T1,T2> );
477  *     }
478  *  };
479  *  template<typename T1, typename T2>
480  *  const volatile int
481  *  D_registrar<T1,T2>::registered = D_registrar<T1,T2>::_register()
482  *
483  *  namespace utilib {
484  *     template<typename T1, typename T2>
485  *     int serial_transform( SerialObject::elementList_t& serial,
486  *                           std::list<T1,T2>& data,  bool serialize )
487  *     {
488  *        D_registrar<T1,T2>::registered || D_registrar<T1,T2>::_register();
489  *        AnyFixedRef tmp = data;
490  *        return Serializer().transform_impl( typeid(data), serial,
491  *                                            tmp, serialize );
492  *     }
493  *  } // namespace (local)
494  *  \endcode
495  *
496  *  While this approach has been observed to be successful, it relies on
497  *  the uninitialized \c registered variable to default to \c false.
498  *  While in some instances this may be accuralte, in general it is not
499  *  safe to rely on uninitialized values.  A more reliable alternative
500  *  is to provide another level of indirection:
501  *
502  *  \code
503  *  template<typename T1, typename T2>
504  *  struct D_registrar {
505  *     static const volatile int auto_register;
506  *     const int registered() {
507  *        static const int ans = Serializer().register_serializer<D<T1,T2> >
508  *           ( std::string("D;") + mangledName(typeid(T1)) + ";"
509  *             + mangledName(typeid(T2)), serialize_D<T1,T2> );
510  *        return ans;
511  *     }
512  *  };
513  *  template<typename T1, typename T2>
514  *  const volatile int
515  *  D_registrar<T1,T2>::auto_register = D_registrar<T1,T2>::registered()
516  *
517  *  namespace utilib {
518  *     template<typename T1, typename T2>
519  *     int serial_transform( SerialObject::elementList_t& serial,
520  *                           std::list<T1,T2>& data,  bool serialize )
521  *     {
522  *        (void)&D_registrar<T1,T2>::auto_register;
523  *        D_registrar<T1,T2>::registered();
524  *        AnyFixedRef tmp = data;
525  *        return Serializer().transform_impl( typeid(data), serial,
526  *                                            tmp, serialize );
527  *     }
528  *  } // namespace (local)
529  *  \endcode
530  *
531  *  While this solution is more robust, it imposes the additional
532  *  overhead of a function call for \em every serialization.  The
533  *  preferred mode is to simply not perform any serialization actions
534  *  until after entry into \c main().
535  *
536  *  \par Providing a user-defined name
537  *
538  *  The user-defined class name provides the Serializer with a unique
539  *  compiler-independent "human-readable" form of the class name.
540  *  Internally the Serializer relies strictly on the type_info structure
541  *  and the mangled type name returned by utilib::mangledName() [\b NB:
542  *  ALWAYS use \c utilib::mangledName() and \em NOT \c
543  *  std::type_info::name() because Microsoft's Visual C++ implementation
544  *  of \c std::type_info::name() does NOT return the mangled name].
545  *  However, C++ mangling rules are compiler-dependent and keying off
546  *  them would restrict serialized data from a program to only be
547  *  readable by other programs (or instances of the same program)
548  *  compiled by the same compiler.  To alleviate this, we build a
549  *  secondary user-specified naming system to use for storing data in a
550  *  more generic format.
551  *
552  *  A general rule for generating a user-defined name is to use the
553  *  human-readable class name, \b including any namespaces.
554  *
555  *  While the process of giving unique names for standard classes is
556  *  relatively straightforward, doing so for each instantiation of a
557  *  template class is tedious at best.  To relieve part of this burden,
558  *  the Serializer contains explicit support for recursively resolving
559  *  the registered names of template parameters for you.  To register a
560  *  serializer for a template class, the "user-defined" name is
561  *  typically the name of your class, followed by the \em mangled type
562  *  names for each of the template arguments (all fields separated by
563  *  semicolons).  For example, given a class B templated on two types,
564  *  the registration for the instance <tt>B<int,std::vector<double>
565  *  ></tt> would be:
566  *
567  *  \code
568  *  template<typename T1, typename T2>
569  *  class B
570  *  {
571  *     // ...
572  *  private:
573  *     static int serializer( utilib::SerialObject::elementList_t & serial,
574  *                            utilib::Any & data, bool serialize )
575  *     static const volatile int serializer_registered;
576  *  };
577  *
578  *  template<>
579  *  const volatile int B<int, std::vector<double> >::serializer_registered
580  *     = Serializer().register_serializer<B<int, std::vector<double> > >
581  *        ( std::string("B;") + utilib::mangledName(typeid(int)) + ";"
582  *            + utilib::mangledName(typeid(std::vector<double>)),
583  *          B<int, std::vector<double> >::serializer );
584  *  \endcode
585  *
586  *  While awkward for single instantiations, this approach allows the
587  *  registration itself to be templitized, thus supporting "automatic"
588  *  registration (see the registration discuaaion above, ::Serialize(),
589  *  and the STL_SerialRegistrars and STL_Serializers namespaces):
590  *
591  *  \code
592  *  template<typename T1, typename T2>
593  *  const volatile int B<T1,T2>::serializer_registered
594  *     = Serializer().register_serializer<B<T1,T2> >
595  *        ( std::string("B;") + utilib::mangledName(typeid(T1)) + ";"
596  *            + utilib::mangledName(typeid(T2)),
597  *          B<T1,T2>::serializer );
598  *  \endcode
599  */
600 class Serialization_Manager
601 {
602 public:
603    /// A flag indicating the endianness of this platform
604    static const unsigned char Endian;
605 
606    /// Constructor - registers standard C++ POD types
607    Serialization_Manager();
608    /// Destructor
609    ~Serialization_Manager();
610 
611    /// Retrieve the typeinfo for the specified type key
612    const std::type_info* get_typeinfo(size_t key);
613 
614    /// Retrieve the user-defined name for the specified type key
615    std::string get_username(size_t key);
616 
617    /// Return true if the key is a POD
618    bool is_pod(size_t key);
619 
620    /// Return true if the key is a POD
621    int get_pod_length(size_t key);
622 
623    /// Retrieve the type key for the specified user-defined name
624    size_t get_keyid(std::string user_name);
625 
626    /// Explicit alias for get_keyid(string) to avoid ambiguity under Solaris
get_keyid(const char * user_name)627    size_t get_keyid(const char* user_name)
628    { return get_keyid(std::string(user_name)); }
629 
630    /// Retrieve the type key for the specified typeinfo
631    size_t get_keyid(const std::type_info &type);
632 
633    /// Set whether POD transformations are into text format instead of binary
set_pod_text_mode(bool pod_text_mode)634    void set_pod_text_mode(bool pod_text_mode)
635    { serialize_pod_as_text = pod_text_mode; }
636 
637    /// Perform the serialize/deserialize transformation
638    int transform_impl(const std::type_info& type,
639                       SerialObject::elementList_t& serial,
640                       AnyFixedRef& data,
641                       bool serialize);
642 
643    /// Register a new serialization function (use the default initializer)
644    template<typename T>
register_serializer(std::string name,transform_fcn fcn)645    int register_serializer(std::string name, transform_fcn fcn)
646    {
647       return register_serializer<T>( name, fcn, &DefaultInitializer<T> );
648    }
649 
650    /// Register a new serialization function and the specified initializer
651    template<typename T>
register_serializer(std::string name,transform_fcn fcn,initialization_fcn init)652    int register_serializer( std::string name,
653                             transform_fcn fcn, initialization_fcn init )
654    {
655       return register_serializer( typeid(T), name, -1, fcn, NULL, NULL, init );
656    }
657 
658    /// Register a new POD serialization function (use the default initializer)
659    template<typename T>
660    int register_serializer(std::string name, pod_transform_fcn fcn,
661                            pod_text_transform_fcn tfcn = NULL,
662                            int size = static_cast<int>(sizeof(T)) )
663    {
664       return register_serializer<T>( name, fcn, tfcn, size,
665                                      &DefaultInitializer<T> );
666    }
667 
668    /// Register a new POD serialization function and the specified initializer
669    template<typename T>
register_serializer(std::string name,pod_transform_fcn fcn,pod_text_transform_fcn tfcn,int size,initialization_fcn init)670    int register_serializer( std::string name, pod_transform_fcn fcn,
671                             pod_text_transform_fcn tfcn, int size,
672                             initialization_fcn init )
673    {
674       return register_serializer(typeid(T), name, size, NULL, fcn, tfcn, init);
675    }
676 
677 
678    /// Debugging function: list all known transformation functions
679    void list_serializers(std::ostream& os);
680 
681 public:  // sub-classes
682 
683    /// The standard default initializer: use the class default constructor
684    template<typename T>
DefaultInitializer(Any & data)685    static void DefaultInitializer(Any& data)
686    {
687       data.set<T>();
688    }
689 
690 private:  // sub-classes
691    typedef std::pair<std::string, size_t>                    typename_pair_t;
692    typedef std::map<std::string, size_t>                     typename_map_t;
693    typedef std::pair<const std::type_info*, size_t>          type_pair_t;
694    typedef std::map<const std::type_info*, size_t>           type_map_t;
695    typedef std::pair<std::string, typename_map_t::iterator>  username_pair_t;
696    typedef std::map<std::string, typename_map_t::iterator>   username_map_t;
697 
698    /// Container for holding serializer information about a type
699    struct MappingFunctions {
700       initialization_fcn  init;          ///< initialization: return new object
701       transform_fcn       transform;     ///< serialize to/from SerialObject
702       pod_transform_fcn   pod_transform; ///< serialize to/from SerialPOD
703       pod_text_transform_fcn    pod_txt_xform; ///< serialize POD to/from text
704       const std::type_info*  typeinfo;   ///< The main type_info for this type
705       std::string               raw_user_name; ///< Name specified by user
706       int                       pod_size;      ///< Data size (-1==variable)
707       username_map_t::iterator  username;      ///< Ref.s to resolved user name
708    };
709 
710 private:  // methods
711    /// Actual method to register a new serializer with the system
712    int register_serializer( const std::type_info& type,
713                             std::string name,
714                             int pod_size,
715                             transform_fcn t_fcn,
716                             pod_transform_fcn p_fcn,
717                             pod_text_transform_fcn pt_fcn,
718                             initialization_fcn i_fcn);
719 
720    /// (Utility method) Rebuild the user-defined type name map
721    void rebuild_user_name_map();
722 
723    /// (Utility method) Recursively resolve any templated types for a user name
724    std::string resolve_user_name(std::string mangled);
725 
726 private:  // data
727    /// Map mangled names to the index in the functions vector
728    typename_map_t                 typename_map;
729    /// Map user name to mangled name (actually, iterator into typename_map)
730    username_map_t                 username_map;
731    /// Map type_info to the index in the functions vector
732    type_map_t                     type_map;
733    /// The vector of all serialization information
734    std::vector<MappingFunctions>  functions;
735    /// If true, username_map is out-of-date and must be rebuilt
736    bool                           rebuild_usernames;
737    /// If true, transform_impl will serialize PODs using pod_text_transform_fcn
738    bool                           serialize_pod_as_text;
739 };
740 
741 
742 //-----------------------------------------------------------------------
743 // Declare all STL-based serializers (implemented below)
744 //
745 namespace STL_Serializers {
746 
747 template<typename T>
748 int pair_serializer( SerialObject::elementList_t& serial,
749                      Any& data, bool serialize );
750 
751 template<typename T>
752 int sequence_serializer( SerialObject::elementList_t& serial,
753                          Any& data, bool serialize );
754 
755 template<typename T>
756 int adaptor_serializer( SerialObject::elementList_t& serial,
757                         Any& data, bool serialize );
758 
759 template<typename T>
760 int set_serializer( SerialObject::elementList_t& serial,
761                     Any& data, bool serialize );
762 
763 template<typename T>
764 int map_serializer( SerialObject::elementList_t& serial,
765                     Any& data, bool serialize );
766 
767 } // namespace STL_Serializers
768 
769 
770 
771 //-----------------------------------------------------------------------
772 /** All serialization registrars for standard STL classes.  This set of
773  *  templated namespace-level constants assists in the automagic
774  *  registration of STL template serializers.  The key trick here is to
775  *  get the \b instantiation of the wrapper function (see
776  *  serial_transform() below) to cause the registration of the
777  *  corresponding serializer \b BEFORE Serialize() / Deserialize() is
778  *  ever called.  If we just took care of the registration through a
779  *  static variable within the serialization wrapper function, the
780  *  serializer would not get registered until the first call to the
781  *  serialization wrapper function.  The problem with that is that the
782  *  program may attempt to DEserialize that type (i.e. loading from a
783  *  file) BEFORE ever serializing the type.  Thus, it is critical that
784  *  the registration happens early, preferably before entry into main().
785  *  These templates take care of that.
786  *
787  *  Note that we are using \b both a static volatile variable
788  *  initialization and a registration function.  The static volatile
789  *  initialization causes the serializer registration to occur before
790  *  entry into main().  The definition of the _register() function is
791  *  used below in the serial_transform() template to guard against other
792  *  classes using the serializer before entry into main().  If another
793  *  class (see the BinarySerialStream unit tests) calls the serializer
794  *  during static construction, the static volatile registration flag
795  *  may not yet be initialized.  By testing the flag, and if false,
796  *  explicitly calling the _register() function, automagic registration
797  *  should still correctly occur.
798  */
799 namespace STL_SerialRegistrars {
800 
801 template<typename T1, typename T2>
802 struct pair_registrar {
803    static const volatile int registered;
804 };
805 template<typename T1, typename T2>
806 const volatile int pair_registrar<T1,T2>::registered = Serializer()
807    .template register_serializer<std::pair<T1,T2> >
808    ( std::string("std::pair;")
809      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
810      STL_Serializers::pair_serializer<std::pair<T1,T2> > );
811 
812 
813 
814 template<typename T1, typename T2>
815 struct list_registrar {
816    static const volatile int registered;
817 };
818 template<typename T1, typename T2>
819 const volatile int list_registrar<T1,T2>::registered = Serializer()
820    .template register_serializer<std::list<T1,T2> >
821    ( std::string("std::list;")
822      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
823      STL_Serializers::sequence_serializer<std::list<T1,T2> > );
824 
825 template<typename T1, typename T2>
826 struct vector_registrar {
827    static const volatile int registered;
828 };
829 template<typename T1, typename T2>
830 const volatile int vector_registrar<T1,T2>::registered = Serializer()
831    .template register_serializer<std::vector<T1,T2> >
832    ( std::string("std::vector;")
833      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
834      STL_Serializers::sequence_serializer<std::vector<T1,T2> > );
835 
836 template<typename T1, typename T2>
837 struct deque_registrar {
838    static const volatile int registered;
839 };
840 template<typename T1, typename T2>
841 const volatile int deque_registrar<T1,T2>::registered = Serializer()
842    .template register_serializer<std::deque<T1,T2> >
843    ( std::string("std::deque;")
844      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
845      STL_Serializers::sequence_serializer<std::deque<T1,T2> > );
846 
847 
848 
849 template<typename T1, typename T2>
850 struct queue_registrar {
851    static const volatile int registered;
852 };
853 template<typename T1, typename T2>
854 const volatile int queue_registrar<T1,T2>::registered = Serializer()
855    .template register_serializer<std::queue<T1,T2> >
856    ( std::string("std::queue;")
857      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
858      STL_Serializers::adaptor_serializer<std::queue<T1,T2> > );
859 
860 template<typename T1, typename T2>
861 struct stack_registrar {
862    static const volatile int registered;
863 };
864 template<typename T1, typename T2>
865 const volatile int stack_registrar<T1,T2>::registered = Serializer()
866    .template register_serializer<std::stack<T1,T2> >
867    ( std::string("std::stack;")
868      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)),
869      STL_Serializers::adaptor_serializer<std::stack<T1,T2> > );
870 
871 template<typename T1, typename T2, typename T3>
872 struct priority_queue_registrar {
873    static const volatile int registered;
874 };
875 template<typename T1, typename T2, typename T3>
876 const volatile int priority_queue_registrar<T1,T2,T3>::registered =Serializer()
877    .template register_serializer<std::priority_queue<T1,T2,T3> >
878    ( std::string("std::priority_queue;") + mangledName(typeid(T1)) + ";"
879      + mangledName(typeid(T2)) + ";" + mangledName(typeid(T3)),
880      STL_Serializers::adaptor_serializer<std::priority_queue<T1,T2,T3> > );
881 
882 
883 
884 template<typename T1, typename T2, typename T3>
885 struct set_registrar {
886    static const volatile int registered;
887 };
888 template<typename T1, typename T2, typename T3>
889 const volatile int set_registrar<T1,T2,T3>::registered = Serializer()
890    .template register_serializer<std::set<T1,T2,T3> >
891    ( std::string("std::set;") + mangledName(typeid(T1)) + ";"
892      + mangledName(typeid(T2)) + ";" + mangledName(typeid(T3)),
893      STL_Serializers::set_serializer<std::set<T1,T2,T3> > );
894 
895 template<typename T1, typename T2, typename T3>
896 struct multiset_registrar {
897    static const volatile int registered;
898 };
899 template<typename T1, typename T2, typename T3>
900 const volatile int multiset_registrar<T1,T2,T3>::registered = Serializer()
901    .template register_serializer<std::multiset<T1,T2,T3> >
902    ( std::string("std::multiset;") + mangledName(typeid(T1)) + ";"
903      + mangledName(typeid(T2)) + ";" + mangledName(typeid(T3)),
904      STL_Serializers::set_serializer<std::multiset<T1,T2,T3> > );
905 
906 
907 
908 template<typename T1, typename T2, typename T3, typename T4>
909 struct map_registrar {
910    static const volatile int registered;
911 };
912 template<typename T1, typename T2, typename T3, typename T4>
913 const volatile int map_registrar<T1,T2,T3,T4>::registered = Serializer()
914    .template register_serializer<std::map<T1,T2,T3,T4> >
915    ( std::string("std::map;")
916      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2))
917      + ";" + mangledName(typeid(T3)) + ";" + mangledName(typeid(T4)),
918      STL_Serializers::map_serializer<std::map<T1,T2,T3,T4> > );
919 
920 template<typename T1, typename T2, typename T3, typename T4>
921 struct multimap_registrar {
922    static const volatile int registered;
923 };
924 template<typename T1, typename T2, typename T3, typename T4>
925 const volatile int multimap_registrar<T1,T2,T3,T4>::registered = Serializer()
926    .template register_serializer<std::multimap<T1,T2,T3,T4> >
927    ( std::string("std::multimap;")
928      + mangledName(typeid(T1)) + ";" + mangledName(typeid(T2)) + ";"
929      + mangledName(typeid(T3)) + ";" + mangledName(typeid(T4)),
930      STL_Serializers::map_serializer<std::multimap<T1,T2,T3,T4> > );
931 
932 } // namespace STL_SerialRegistrars
933 
934 
935 
936 //-----------------------------------------------------------------------
937 //
938 
939 /** \param[in,out] serial  A SerialObject list
940  *  \param[in,out] data    A reference to the variable to serialize
941  *  \param[in] serialize   Indicates whether to serialize or deserialize
942  *  \return 0 on success, <>0 on error.
943  *
944  *  serial_transform() is a "convenience" wrapper function around the
945  *  core Serialization_Manager::transform_impl() function.  To provide
946  *  implicit support for template classes (including the STL), we need
947  *  to assure that the serialization for a particular template
948  *  instantiation is registered before the first call to
949  *  Serialization_Manager::transform_impl().  The templated overloads of
950  *  this namespace-level wrapper function guarantee that the
951  *  registration takes place.
952  *
953  *  This specific function is designed to correctly deal with
954  *  serializing and deserializing Any variables (with special care to
955  *  correctly process empty Any data).
956  *
957  *  Each call to serial_transform() with \a serialize == true will
958  *  serialize the variable referenced by \a data into a SerialObject and
959  *  push the resulting object onto the end of the \a serial list.  Each
960  *  call to serial_transform with \a serialize == false will remove the
961  *  SerialObject from the front of the \a serial list and deserialize it
962  *  into the Any \a data object.
963  */
964 int serial_transform(SerialObject::elementList_t& serial,
965                      Any& data,  bool serialize);
966 
967 template<typename T>
serial_transform(SerialObject::elementList_t & serial,T & data,bool serialize)968 int serial_transform(SerialObject::elementList_t& serial,
969                      T& data,  bool serialize)
970 {
971    AnyFixedRef tmp = data;
972    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
973 }
974 
975 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::pair<T1,T2> & data,bool serialize)976 int serial_transform(SerialObject::elementList_t& serial,
977                      std::pair<T1,T2>& data,  bool serialize)
978 {
979    (void)&STL_SerialRegistrars::pair_registrar<T1,T2>::registered;
980    AnyFixedRef tmp = data;
981    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
982 }
983 
984 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::list<T1,T2> & data,bool serialize)985 int serial_transform(SerialObject::elementList_t& serial,
986                      std::list<T1,T2>& data,  bool serialize)
987 {
988    (void)&STL_SerialRegistrars::list_registrar<T1,T2>::registered;
989    AnyFixedRef tmp = data;
990    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
991 }
992 
993 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::vector<T1,T2> & data,bool serialize)994 int serial_transform(SerialObject::elementList_t& serial,
995                      std::vector<T1,T2>& data,  bool serialize)
996 {
997    (void)&STL_SerialRegistrars::vector_registrar<T1,T2>::registered;
998    AnyFixedRef tmp = data;
999    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1000 }
1001 
1002 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::deque<T1,T2> & data,bool serialize)1003 int serial_transform(SerialObject::elementList_t& serial,
1004                      std::deque<T1,T2>& data,  bool serialize)
1005 {
1006    (void)&STL_SerialRegistrars::deque_registrar<T1,T2>::registered;
1007    AnyFixedRef tmp = data;
1008    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1009 }
1010 
1011 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::queue<T1,T2> & data,bool serialize)1012 int serial_transform(SerialObject::elementList_t& serial,
1013                      std::queue<T1,T2>& data,  bool serialize)
1014 {
1015    (void)&STL_SerialRegistrars::queue_registrar<T1,T2>::registered;
1016    AnyFixedRef tmp = data;
1017    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1018 }
1019 
1020 template<typename T1, typename T2>
serial_transform(SerialObject::elementList_t & serial,std::stack<T1,T2> & data,bool serialize)1021 int serial_transform(SerialObject::elementList_t& serial,
1022                      std::stack<T1,T2>& data,  bool serialize)
1023 {
1024    (void)&STL_SerialRegistrars::stack_registrar<T1,T2>::registered;
1025    AnyFixedRef tmp = data;
1026    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1027 }
1028 
1029 template<typename T1, typename T2, typename T3>
serial_transform(SerialObject::elementList_t & serial,std::priority_queue<T1,T2,T3> & data,bool serialize)1030 int serial_transform(SerialObject::elementList_t& serial,
1031                      std::priority_queue<T1,T2,T3>& data,  bool serialize)
1032 {
1033    (void)&STL_SerialRegistrars::priority_queue_registrar<T1,T2,T3>::registered;
1034    AnyFixedRef tmp = data;
1035    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1036 }
1037 
1038 template<typename T1, typename T2, typename T3>
serial_transform(SerialObject::elementList_t & serial,std::set<T1,T2,T3> & data,bool serialize)1039 int serial_transform(SerialObject::elementList_t& serial,
1040                      std::set<T1,T2,T3>& data,  bool serialize)
1041 {
1042    (void)&STL_SerialRegistrars::set_registrar<T1,T2,T3>::registered;
1043    AnyFixedRef tmp = data;
1044    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1045 }
1046 
1047 template<typename T1, typename T2, typename T3>
serial_transform(SerialObject::elementList_t & serial,std::multiset<T1,T2,T3> & data,bool serialize)1048 int serial_transform(SerialObject::elementList_t& serial,
1049                      std::multiset<T1,T2,T3>& data,  bool serialize)
1050 {
1051    (void)&STL_SerialRegistrars::multiset_registrar<T1,T2,T3>::registered;
1052    AnyFixedRef tmp = data;
1053    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1054 }
1055 
1056 template<typename T1, typename T2, typename T3, typename T4>
serial_transform(SerialObject::elementList_t & serial,std::map<T1,T2,T3,T4> & data,bool serialize)1057 int serial_transform(SerialObject::elementList_t& serial,
1058                      std::map<T1,T2,T3,T4>& data,  bool serialize)
1059 {
1060    (void)&STL_SerialRegistrars::map_registrar<T1,T2,T3,T4>::registered;
1061    AnyFixedRef tmp = data;
1062    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1063 }
1064 
1065 template<typename T1, typename T2, typename T3, typename T4>
serial_transform(SerialObject::elementList_t & serial,std::multimap<T1,T2,T3,T4> & data,bool serialize)1066 int serial_transform(SerialObject::elementList_t& serial,
1067                      std::multimap<T1,T2,T3,T4>& data,  bool serialize)
1068 {
1069    (void)&STL_SerialRegistrars::multimap_registrar<T1,T2,T3,T4>::registered;
1070    AnyFixedRef tmp = data;
1071    return Serializer().transform_impl(typeid(data), serial, tmp, serialize);
1072 }
1073 
1074 
1075 /** \param[in] data  A reference to the variable to serialize
1076  *  \param[in] pod_text_mode Indicate if POD data should be serialized
1077  *     as a binary vector or a text-based vector (see utilib::XMLSerialStream).
1078  *  \return The serialized object (as a SerialObject)
1079  *
1080  *  This will take the object referenced by \a data and serialize it,
1081  *  returning the resulting SerialObject.  This function is a
1082  *  convenience wrapper around serial_transform().
1083  */
1084 template<typename T>
1085 SerialObject Serialize(const T& data, bool pod_text_mode = false)
1086 {
1087    Serializer().set_pod_text_mode(pod_text_mode);
1088 
1089    SerialObject::elementList_t tmp;
1090    int ans = serial_transform(tmp, const_cast<T&>(data), true);
1091    if ( ans != 0 )
1092    {
1093       EXCEPTION_MNGR(std::runtime_error, "Serialize(): "
1094                      "Serialization failed for '"
1095                      << typeid(T).name() << "' (Error " << ans << ")");
1096    }
1097    if ( tmp.empty() || ( ++(tmp.begin()) != tmp.end() ) )
1098    {
1099       EXCEPTION_MNGR(std::runtime_error, "Serialize(): "
1100                      "[internal error] returned invalid object count for '"
1101                      << typeid(T).name() << "'");
1102    }
1103    return tmp.front();
1104 }
1105 
1106 /** \param[in] serial  A serialized object
1107  *  \return The expanded object specified by \a serial contained in an Any
1108  *
1109  *  This will deserialize any SerialObject and return the expanded
1110  *  object.  This function is a convenience wrapper around
1111  *  serial_transform().
1112  */
1113 Any Deserialize(SerialObject &serial);
1114 
1115 
1116 //-----------------------------------------------------------------------
1117 /** All serialization functions for standard STL classes.
1118  */
1119 namespace STL_Serializers {
1120 
1121 template<typename T>
pair_serializer(SerialObject::elementList_t & serial,Any & data,bool serialize)1122 int pair_serializer( SerialObject::elementList_t& serial,
1123                      Any& data, bool serialize )
1124 {
1125    T& tmp = const_cast<T&>(data.template expose<T>());
1126    int ans = serial_transform(serial, tmp.first, serialize);
1127    if ( ans != 0 )
1128       return ans;
1129    return serial_transform(serial, tmp.second, serialize);
1130 }
1131 
1132 
1133 template<typename T>
sequence_serializer(SerialObject::elementList_t & serial,Any & data,bool serialize)1134 int sequence_serializer( SerialObject::elementList_t& serial,
1135                          Any& data, bool serialize )
1136 {
1137    T& tmp = const_cast<T&>(data.template expose<T>());
1138    if ( ! serialize )
1139       tmp.resize(serial.size());
1140 
1141    int ans = 0;
1142    typename T::iterator it = tmp.begin();
1143    typename T::iterator itEnd = tmp.end();
1144    for ( ; it != itEnd; ++it )
1145       if ( 0 != (ans = serial_transform(serial, *it, serialize)) )
1146          return ans;
1147 
1148    return 0;
1149 }
1150 
1151 /// Helper class to gain access to protected sequence container in adaptor
1152 template<typename T>
1153 class ModifiedSequenceAdaptor : public T
1154 {
1155 public:
sub_transform(SerialObject::elementList_t & serial,bool serialize)1156    int sub_transform(SerialObject::elementList_t& serial, bool serialize)
1157    {
1158       return serial_transform(serial, T::c, serialize);
1159    }
1160 };
1161 
1162 template<typename T>
adaptor_serializer(SerialObject::elementList_t & serial,Any & data,bool serialize)1163 int adaptor_serializer( SerialObject::elementList_t& serial,
1164                          Any& data, bool serialize )
1165 {
1166    T& tmp = const_cast<T&>(data.template expose<T>());
1167    return reinterpret_cast<ModifiedSequenceAdaptor<T>&>(tmp)
1168       .sub_transform(serial, serialize);
1169 }
1170 
1171 
1172 template<typename T>
set_serializer(SerialObject::elementList_t & serial,Any & data,bool serialize)1173 int set_serializer( SerialObject::elementList_t& serial,
1174                     Any& data, bool serialize )
1175 {
1176    int ans = 0;
1177    T& tmp = const_cast<T&>(data.template expose<T>());
1178    if ( serialize )
1179    {
1180       typename T::iterator it = tmp.begin();
1181       typename T::iterator itEnd = tmp.end();
1182       for ( ; it != itEnd; ++it )
1183          if ( 0 != (ans = serial_transform(serial, *it, serialize)) )
1184             return ans;
1185    }
1186    else
1187    {
1188       while ( ! serial.empty() )
1189       {
1190          AnyFixedRef i;
1191          ans = Serializer().transform_impl(typeid(void), serial, i, serialize);
1192          if ( ans != 0 )
1193             return ans;
1194          tmp.insert(tmp.end(), i.template expose<typename T::value_type>());
1195       }
1196    }
1197 
1198    return 0;
1199 }
1200 
1201 template<typename T>
map_serializer(SerialObject::elementList_t & serial,Any & data,bool serialize)1202 int map_serializer( SerialObject::elementList_t& serial,
1203                     Any& data, bool serialize )
1204 {
1205    // Ideally, we would use the set_serializer above for all associative
1206    // containers.  Unfortunately, the value_type for maps is
1207    // std::pair<const T1, T2>.  As a result, we need to reinterpret it
1208    // as the non-const pair<T1,T2> BEFORE we stick it into an Any
1209    // (because the default "const T1" is not assignable and thus will
1210    // not compile).
1211    //
1212    // NB: This is further complicated because GCC deviates from the SGI
1213    // standard: SGI publishes T2 as map::data_type, while GCC uses
1214    // map::mapped_type.  To get around this, we use
1215    // map::value_type::second_type (i.e. get T2 from the underlying
1216    // pair), which hopefully will be more portable...
1217    typedef std::pair<typename T::key_type, typename T::value_type::second_type>
1218       nonConstPair_t;
1219 
1220    int ans = 0;
1221    T& tmp = const_cast<T&>(data.template expose<T>());
1222    if ( serialize )
1223    {
1224       typename T::iterator it = tmp.begin();
1225       typename T::iterator itEnd = tmp.end();
1226       for ( ; it != itEnd; ++it )
1227       {
1228          nonConstPair_t &element = reinterpret_cast<nonConstPair_t&>(*it);
1229          if ( 0 != (ans = serial_transform(serial, element, serialize)) )
1230             return ans;
1231       }
1232    }
1233    else
1234    {
1235       while ( ! serial.empty() )
1236       {
1237          AnyFixedRef i;
1238          ans = Serializer().transform_impl(typeid(void), serial, i, serialize);
1239          if ( ans != 0 )
1240             return ans;
1241          tmp.insert( tmp.end(), i.template expose<nonConstPair_t>() );
1242       }
1243    }
1244 
1245    return 0;
1246 }
1247 
1248 } // namespace STL_Serializers
1249 
1250 } // namespace utilib
1251 
1252 #endif // utilib_Serialize_h
1253