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.cpp
14  */
15 
16 #include <utilib/Serialize.h>
17 #include <utilib/exception_mngr.h>
18 
19 using std::cerr;
20 using std::endl;
21 
22 using std::map;
23 using std::pair;
24 using std::vector;
25 using std::string;
26 using std::type_info;
27 
28 
29 namespace utilib {
30 
31 namespace { // local namespace for endian detection
32 
33 const char template_separator = ';';
34 
35 const int int_bytes = (( 0 << ( 8 * (3 % sizeof(int))) ) +
36                        ( 1 << ( 8 * (2 % sizeof(int))) ) +
37                        ( 2 << ( 8 * (1 % sizeof(int))) ) +
38                        ( 3 << ( 8 * (0 % sizeof(int))) ));
39 
40 } // namespace utilib::(local)
41 
42 /** Detect the endian-ness of this platform.
43  *
44  *  This code should be safe for compilers with both 2-byte and 4-byte
45  *  ints.  Common values are:
46  *     - e4 (11 10 01 00) = 4-byte little-endian (Intel)
47  *     - 1b (00 01 10 11) = 4-byte big-endian
48  *     - 22 (00 10 00 10) = 2-byte little endian
49  *     - 88 (10 00 10 00) = 2-byte big endian
50  */
51 const unsigned char Serialization_Manager::Endian =
52    (( (3 & reinterpret_cast<const char*>(&int_bytes)[0 % sizeof(int)]) << 6 ) +
53     ( (3 & reinterpret_cast<const char*>(&int_bytes)[1 % sizeof(int)]) << 4 ) +
54     ( (3 & reinterpret_cast<const char*>(&int_bytes)[2 % sizeof(int)]) << 2 ) +
55     ( (3 & reinterpret_cast<const char*>(&int_bytes)[3 % sizeof(int)]) ));
56 
57 
58 /// local namespace for default POD serialization functions
59 namespace POD_serializers {
60 
61 template<typename T>
POD_serializer(SerialPOD & serial,Any & data,bool serialize)62 int POD_serializer(SerialPOD& serial, Any& data, bool serialize)
63 {
64    if ( serialize )
65       serial.set(&data.template expose<T>(), sizeof(T));
66    else
67    {
68       if ( serial.size() != sizeof(T) )
69          EXCEPTION_MNGR(serializer_bad_pod_size, "POD_serializer(): "
70                         "SerialPOD data size does not match destination type");
71 
72       memcpy( &const_cast<T&>(data.template expose<T>()),
73 	      serial.data(), serial.size() );
74    }
75    return 0;
76 }
77 
78 template<>
POD_serializer(SerialPOD & serial,Any & data,bool serialize)79 int POD_serializer<std::string>(SerialPOD& serial, Any& data, bool serialize)
80 {
81    const std::string &str = data.expose<std::string>();
82    if ( serialize )
83       serial.set(str.c_str(), str.size());
84    else
85       data.set(std::string(serial.data(), serial.size()));
86    return 0;
87 }
88 
89 
90 template<typename T>
POD_text_serializer(std::string & serial,Any & data,bool serialize)91 int POD_text_serializer(std::string& serial, Any& data, bool serialize)
92 {
93    std::stringstream s;
94    if ( serialize )
95    {
96       s << data.template expose<T>();
97       serial = s.str();
98    }
99    else
100    {
101       s.str(serial);
102       s >> const_cast<T&>(data.template expose<T>()) >> std::ws;
103    }
104 
105    if ( s.bad() || s.fail() )
106       return error::Serialization::BadPODTextConversion;
107    else if ( ! serialize )
108       return s.eof() ? 0 : error::Serialization::UnconvertedPODText;
109    else
110       return 0;
111 }
112 
113 template<>
POD_text_serializer(std::string & serial,Any & data,bool serialize)114 int POD_text_serializer<float>(std::string& serial, Any& data, bool serialize)
115 {
116    std::stringstream s;
117    if ( serialize )
118    {
119       s.setf(std::ios::floatfield);
120       s.precision(FLT_DIG+2);
121       s << data.expose<float>();
122       serial = s.str();
123    }
124    else
125    {
126       s.str(serial);
127       s >> const_cast<float&>(data.expose<float>()) >> std::ws;
128    }
129 
130    if ( s.bad() || s.fail() )
131       return error::Serialization::BadPODTextConversion;
132    else if ( ! serialize )
133       return s.eof() ? 0 : error::Serialization::UnconvertedPODText;
134    else
135       return 0;
136 }
137 
138 template<>
POD_text_serializer(std::string & serial,Any & data,bool serialize)139 int POD_text_serializer<double>(std::string& serial, Any& data, bool serialize)
140 {
141    std::stringstream s;
142    if ( serialize )
143    {
144       s.setf(std::ios::floatfield);
145       s.precision(DBL_DIG+2);
146       s << data.expose<double>();
147       serial = s.str();
148    }
149    else
150    {
151       s.str(serial);
152       s >> const_cast<double&>(data.expose<double>()) >> std::ws;
153    }
154 
155    if ( s.bad() || s.fail() )
156       return error::Serialization::BadPODTextConversion;
157    else if ( ! serialize )
158       return s.eof() ? 0 : error::Serialization::UnconvertedPODText;
159    else
160       return 0;
161 }
162 
163 template<>
POD_text_serializer(std::string & serial,Any & data,bool serialize)164 int POD_text_serializer<long double>( std::string& serial, Any& data,
165                                       bool serialize )
166 {
167    std::stringstream s;
168    if ( serialize )
169    {
170       s.setf(std::ios::floatfield);
171       s.precision(LDBL_DIG+2);
172       s << data.expose<long double>();
173       serial = s.str();
174    }
175    else
176    {
177       s.str(serial);
178       s >> const_cast<long double&>(data.expose<long double>()) >> std::ws;
179    }
180 
181    if ( s.bad() || s.fail() )
182       return error::Serialization::BadPODTextConversion;
183    else if ( ! serialize )
184       return s.eof() ? 0 : error::Serialization::UnconvertedPODText;
185    else
186       return 0;
187 }
188 
189 template<>
POD_text_serializer(std::string & serial,Any & data,bool serialize)190 int POD_text_serializer<std::string>( std::string& serial, Any& data,
191                                       bool serialize )
192 {
193    if ( serialize )
194       serial = "\"" + data.expose<std::string>() + "\"";
195    else
196    {
197       string::iterator it = serial.begin();
198       string::iterator itEnd = serial.end();
199       // test for empty string or no leading "
200       if (( it == itEnd ) || ( *it != '"' ))
201          return error::Serialization::MissingStringQuote;
202       ++it;
203 
204       // test for string.size() == 1
205       if ( it == itEnd )
206          return error::Serialization::MissingStringQuote;
207       --itEnd;
208       if ( *itEnd != '"' )
209          return error::Serialization::MissingStringQuote;
210 
211       data.set(std::string(it, itEnd));
212    }
213    return 0;
214 }
215 
216 template<>
POD_text_serializer(std::string & serial,Any & data,bool serialize)217 int POD_text_serializer<char>( std::string& serial, Any& data,
218                                bool serialize )
219 {
220    std::stringstream s;
221    if ( serialize )
222    {
223       char c = data.expose<char>();
224       if ( c >= 32 && c <= 126 )
225       {
226          serial = "\'x\'";
227          serial[1] = c;
228       }
229       else
230       {
231          s << static_cast<int>(c);
232          serial = s.str();
233       }
234    }
235    else
236    {
237       if ( serial.empty() )
238          return error::Serialization::BadPODData;
239       if ( serial[0] == '\'' )
240       {
241          if ( serial.size() != 3 || serial[2] != '\'' )
242             return error::Serialization::BadPODData;
243          data.set<char>(serial[1]);
244       }
245       else
246       {
247          s.str(serial);
248          int i = CHAR_MAX + 1;
249          s >> i;
250          if (( i < CHAR_MIN ) || ( i > CHAR_MAX ))
251             return error::Serialization::BadPODTextConversion;
252          const_cast<char&>(data.expose<char>()) = static_cast<char>(i);
253       }
254       s >> std::ws;
255    }
256 
257    if ( s.bad() || s.fail() )
258       return error::Serialization::BadPODTextConversion;
259    else if ( ! serialize )
260       return s.eof() ? 0 : error::Serialization::UnconvertedPODText;
261    else
262       return 0;
263 }
264 
265 #ifndef QUOTE
266 #  define QUOTE(x) _QUOTE(x)
267 #  define _QUOTE(x) #x
268 #endif
269 
270 #define REGISTER_POD(TYPE)                                              \
271    register_serializer<TYPE >( QUOTE(TYPE),                             \
272                                POD_serializers::POD_serializer<TYPE >,  \
273                                POD_serializers::POD_text_serializer<TYPE > )
274 
275 
276 } // namespace utilib::POD_serializers
277 
278 
279 //--------------------------------------------------------------------
280 // Serializer singleton management
281 //
Serializer()282 Serialization_Manager& Serializer()
283 {
284    static Serialization_Manager master_serializer;
285    return master_serializer;
286 }
287 
288 
289 //--------------------------------------------------------------------
290 // SerialPOD members
291 //
set(const void * buffer_src,const size_t length)292 void SerialPOD::set(const void* buffer_src, const size_t length)
293 {
294    buffer.resize(length);
295    memcpy(&buffer[0], buffer_src, length);
296    text_mode = false;
297 }
298 
set(const std::string & buffer_src)299 void SerialPOD::set(const std::string& buffer_src)
300 {
301    size_t size = buffer_src.size();
302    buffer.resize(size);
303    memcpy(&buffer[0], buffer_src.c_str(), size);
304    text_mode = true;
305 }
306 
print(std::ostream & os,std::string indent) const307 void SerialPOD::print(std::ostream& os, std::string indent) const
308 {
309    if ( text_mode )
310       os << ": ";
311    else
312       os << endl << indent << "POD: " << size() << ":";
313    for(size_t i = 0; i < size(); ++i)
314       if ( text_mode )
315          os << buffer[i];
316       else
317          os << " " << static_cast<int>(static_cast<unsigned char>(buffer[i]));
318    os << endl;
319 }
320 
321 
322 //--------------------------------------------------------------------
323 // SerialObject members
324 //
print(std::ostream & os,std::string indent) const325 void SerialObject::print(std::ostream& os, std::string indent) const
326 {
327    os << indent << "type = " << Serializer().get_username(type);
328    if ( data.is_type(typeid(SerialObject::elementList_t)) )
329    {
330       os << endl;
331       SerialObject::elementList_t::const_iterator it =
332          data.expose<SerialObject::elementList_t>().begin();
333       SerialObject::elementList_t::const_iterator itEnd =
334          data.expose<SerialObject::elementList_t>().end();
335       for ( ; it != itEnd; ++it )
336          it->print(os, indent + "   ");
337    }
338    else if ( data.is_type(typeid(SerialPOD)) )
339       data.expose<SerialPOD>().print(os, indent + "   ");
340    else
341       os << endl << indent << "   UNKNOWN DATA! ("
342          << demangledName(data.type()) << ")" << endl;
343 }
344 
345 
346 //--------------------------------------------------------------------
347 // utilib namespace functions
348 //
349 
serial_transform(SerialObject::elementList_t & serial,Any & data,bool serialize)350 int serial_transform(SerialObject::elementList_t& serial,
351                      Any& data,  bool serialize)
352 {
353    AnyFixedRef tmp = data;
354    int ans = Serializer().transform_impl
355       (data.empty() ? typeid(void) : data.type(), serial, tmp, serialize);
356    if ( data.empty() || tmp.empty() )
357       data = tmp;
358    return ans;
359 }
360 
Deserialize(SerialObject & serial)361 Any Deserialize(SerialObject &serial)
362    {
363    SerialObject::elementList_t tmp(1, serial);
364    AnyFixedRef data;
365    int ans = Serializer().transform_impl(typeid(void), tmp, data, false);
366    if ( ans != 0 )
367    {
368       EXCEPTION_MNGR(serialization_error,
369                      "Serialization_Manager::Deserialize()"
370                      ": Deserialization failed for '"
371                      << data.type().name() << "' (Error " << ans << ")");
372    }
373    return data;
374 }
375 
376 //--------------------------------------------------------------------
377 // Serialization_Manager members
378 //
379 
Serialization_Manager()380 Serialization_Manager::Serialization_Manager()
381    : typename_map(),
382      username_map(),
383      type_map(),
384      functions(),
385      rebuild_usernames(true),
386      serialize_pod_as_text(false)
387 {
388    // Reserve some space for the standard transformations
389    functions.reserve(19);
390 
391    // NB: this must be first (so that void gets id 0)
392    register_serializer(typeid(void), "void", 0, NULL, NULL, NULL, NULL);
393 
394    // Several of these registrations may be duplicates - BUT, since it's
395    // all in the same cpp file, the duplicates should be silently
396    // ignored.
397 
398    // NB: according to the C++ standard, the signedness of char is
399    // implementation-specific.  As a result, char, signed char, and
400    // unsigned char are distinct types.  This means that the 'signed
401    // char' registration is explicitly required (or else signed chars
402    // will be silently cast into ints!)
403    REGISTER_POD(char);
404    REGISTER_POD(signed char);
405    REGISTER_POD(unsigned char);
406 
407    REGISTER_POD(short);
408    REGISTER_POD(signed short);
409    REGISTER_POD(unsigned short);
410 
411    REGISTER_POD(int);
412    REGISTER_POD(signed int);
413    REGISTER_POD(unsigned int);
414 
415    REGISTER_POD(long);
416    REGISTER_POD(signed long);
417    REGISTER_POD(unsigned long);
418 
419    REGISTER_POD(float);
420    REGISTER_POD(double);
421    REGISTER_POD(long double);
422 
423    REGISTER_POD(bool);
424 
425    // manually register wchar_t so the text string transform defaults to binary
426    register_serializer<wchar_t>
427       ( "wchar_t", POD_serializers::POD_serializer<wchar_t> );
428    // manually register strings so the name isn't "std::basic_string<*,*>"
429    register_serializer<std::string>
430       ( "std::string",
431         POD_serializers::POD_serializer<std::string>,
432         POD_serializers::POD_text_serializer<std::string>, -1 );
433 }
434 
435 
~Serialization_Manager()436 Serialization_Manager::~Serialization_Manager()
437 {}
438 
439 
440 const std::type_info*
get_typeinfo(size_t key)441 Serialization_Manager::get_typeinfo(size_t key)
442 {
443    if ( key >= functions.size() )
444       return NULL;
445    else
446       return functions[key].typeinfo;
447 }
448 
449 
450 std::string
get_username(size_t key)451 Serialization_Manager::get_username(size_t key)
452 {
453    if ( key >= functions.size() )
454       return "";
455    else
456    {
457       if ( rebuild_usernames )
458          rebuild_user_name_map();
459       username_map_t::iterator it = functions[key].username;
460       return ( it == username_map.end() ? "" : it->first );
461    }
462 }
463 
464 
465 bool
is_pod(size_t key)466 Serialization_Manager::is_pod(size_t key)
467 {
468    if ( key >= functions.size() )
469       return false;
470    else
471       return functions[key].pod_transform != NULL;
472 }
473 
474 
475 int
get_pod_length(size_t key)476 Serialization_Manager::get_pod_length(size_t key)
477 {
478    if ( key >= functions.size() )
479       return -1;
480    else
481       return functions[key].pod_size;
482 }
483 
484 
485 size_t
get_keyid(std::string user_name)486 Serialization_Manager::get_keyid(std::string user_name)
487 {
488    if ( rebuild_usernames )
489       rebuild_user_name_map();
490 
491    username_map_t::iterator u_it = username_map.find(user_name);
492    if ( u_it == username_map.end() )
493       EXCEPTION_MNGR(serializer_unknown_type,
494                      "Serialization_Manager::get_keyid(): "
495                      "unknown user-defined type name, \""
496                      << user_name << "\"");
497    if ( u_it->second == typename_map.end() )
498       EXCEPTION_MNGR(serializer_unknown_type,
499                      "Serialization_Manager::get_keyid(): "
500                      "user-defined type name, \""
501                      << user_name << "\" maps to multiple types");
502 
503    return u_it->second->second;
504 }
505 
506 size_t
get_keyid(const std::type_info & type)507 Serialization_Manager::get_keyid(const std::type_info &type)
508 {
509    type_map_t::iterator t_it = type_map.find(&type);
510    if ( t_it == type_map.end() )
511    {
512       typename_map_t::iterator n_it = typename_map.find(mangledName(type));
513       if ( n_it == typename_map.end() )
514          EXCEPTION_MNGR(serializer_unknown_type,
515                         "Serialization_Manager::get_keyid(): "
516                         "unknown type_info name, \""
517                         << type.name() << "\"");
518       return n_it->second;
519    }
520 
521    return t_it->second;
522 }
523 
524 
525 int
transform_impl(const std::type_info & type,SerialObject::elementList_t & serial,AnyFixedRef & data,bool serialize)526 Serialization_Manager::transform_impl( const std::type_info& type,
527                                        SerialObject::elementList_t& serial,
528                                        AnyFixedRef& data,
529                                        bool serialize )
530 {
531    if ( rebuild_usernames )
532       rebuild_user_name_map();
533 
534    type_map_t::iterator it = type_map.end();
535 
536    if ( serialize )
537    {
538       if ( data.empty() )
539       {
540          // Serialize empty Anys as VOID
541          serial.push_back(SerialObject());
542          return 0;
543       }
544 
545       // find this data type...
546       it = type_map.find(&type);
547       if ( it == type_map.end() )
548       {
549          // check to see if the mangled typename exists...
550          typename_map_t::iterator name_it
551             = typename_map.find(mangledName(type));
552          if ( name_it == typename_map.end() )
553             EXCEPTION_MNGR(serializer_unknown_type,
554                            "Serialization_Manager::transform_impl(): "
555                            "cannot serialize unknown type '"
556                            << type.name() << "'");
557 
558          // insert reference to this typeid for future use
559          it = type_map.insert(type_pair_t(&type,name_it->second)).first;
560       }
561 
562       MappingFunctions &fcns = functions[it->second];
563 
564       // Check for a username conflict
565       if ( fcns.username == username_map.end() )
566          EXCEPTION_MNGR(serialization_error,
567                         "Serialization_Manager::transform_impl(): attempt "
568                         "to serialize an object with a nonunique username.");
569 
570       // Prep the serialization container.
571       serial.push_back(SerialObject(it->second));
572 
573       int ans = 0;
574       // serialize the object
575       if ( fcns.transform != NULL )
576          ans = fcns.transform
577             ( serial.back().data.set<SerialObject::elementList_t>(),
578               data, serialize );
579       else if ( fcns.pod_transform != NULL )
580       {
581          if (( serialize_pod_as_text ) && ( fcns.pod_txt_xform != NULL ))
582          {
583             string buf;
584             ans = fcns.pod_txt_xform( buf, data, serialize );
585             serial.back().data.set<SerialPOD>().set(buf);
586          }
587          else
588             ans = fcns.pod_transform
589                ( serial.back().data.set<SerialPOD>(), data, serialize );
590       }
591       else
592          EXCEPTION_MNGR(serialization_error,
593                         "Serialization_Manager::transform_impl(): "
594                         "NULL serialization function for type '"
595                         << type.name() << "'");
596       return ans;
597    }
598    else
599    {
600       if ( serial.empty() )
601          EXCEPTION_MNGR(serialization_error,
602                         "Serialization_Manager::transform_impl(): "
603                         "SerialObject missing required element.");
604 
605       SerialObject& so = serial.front();
606       if (so.type == 0 )
607       {
608          // Deserialize VOID
609          data.clear();
610          return 0;
611       }
612       if ( so.type >= functions.size() )
613          EXCEPTION_MNGR(serializer_unknown_type,
614                         "Serialization_Manager::transform_impl(): "
615                         "SerialObject contains unknown type id.");
616 
617       MappingFunctions &fcns = functions[so.type];
618       // Check for a username conflict
619       if ( fcns.username == username_map.end() )
620          EXCEPTION_MNGR(serialization_error,
621                         "Serialization_Manager::transform_impl(): attempt "
622                         "to deserialize an object with a nonunique username.");
623 
624       // Initialize the result data
625       if ( fcns.init == NULL )
626          EXCEPTION_MNGR(serialization_error,
627                         "Serialization_Manager::transform_impl(): "
628                         "NULL initialization function for id " << so.type);
629       fcns.init(data);
630       if ( data.empty() )
631       {
632          cerr << "WARNING: Serialization_Manager::transform_impl(): "
633             "initialization function for " << type.name()
634               << " resulted in an empty Any." << endl
635               << "         This will likely cause random segmentation "
636             "faults." << endl;
637       }
638 
639       // deserialize the object
640       int ans = 0;
641       if ( fcns.transform != NULL )
642          ans = fcns.transform
643             ( const_cast<SerialObject::elementList_t&>
644               (so.data.expose<SerialObject::elementList_t>()),
645               data, serialize );
646       else if ( fcns.pod_transform != NULL )
647       {
648          SerialPOD& pod = const_cast<SerialPOD&>(so.data.expose<SerialPOD>());
649          if ( pod.is_text_mode() )
650          {
651             string buf = string(pod.data(), pod.size());
652             assert(fcns.pod_txt_xform != NULL);
653             ans = fcns.pod_txt_xform( buf, data, serialize );
654          }
655          else
656             ans = fcns.pod_transform( pod, data, serialize );
657       }
658       else
659          EXCEPTION_MNGR(serialization_error,
660                         "Serialization_Manager::transform_impl(): "
661                         "NULL deserialization function for id " << so.type);
662 
663       serial.pop_front();
664       return ans;
665    }
666 
667    // Cannot get here...
668 }
669 
670 
671 void
list_serializers(std::ostream & os)672 Serialization_Manager::list_serializers(std::ostream& os)
673 {
674    if ( rebuild_usernames )
675       rebuild_user_name_map();
676 
677    os << "Known serializers:" << endl;
678    username_map_t::iterator it = username_map.begin();
679    username_map_t::iterator itEnd = username_map.end();
680    size_t max = 0;
681    for ( ; it != itEnd; ++it )
682       max = ( max < it->first.size() ? it->first.size() : max );
683 
684    for (it = username_map.begin() ; it != itEnd; ++it )
685       os << "   " << std::left << std::setw(max) << it->first << "   [ "
686          << ( it->second == typename_map.end()
687               ? "CONFLICT" : it->second->first )
688          << " ]" << endl;
689 }
690 
691 
692 int
register_serializer(const std::type_info & type,std::string name,int pod_size,transform_fcn t_fcn,pod_transform_fcn p_fcn,pod_text_transform_fcn pt_fcn,initialization_fcn i_fcn)693 Serialization_Manager::register_serializer( const std::type_info& type,
694                                             std::string name,
695                                             int pod_size,
696                                             transform_fcn t_fcn,
697                                             pod_transform_fcn p_fcn,
698                                             pod_text_transform_fcn pt_fcn,
699                                             initialization_fcn i_fcn)
700 {
701    pair<typename_map_t::iterator,bool> ans = typename_map.insert
702       (typename_pair_t(mangledName(type), functions.size()));
703    if ( ans.second )
704    {
705       // New registration
706       type_map[&type] = functions.size();
707 
708       functions.push_back(MappingFunctions());
709       MappingFunctions &m = functions.back();
710       m.init = i_fcn;
711       m.transform = t_fcn;
712       m.pod_transform = p_fcn;
713       m.pod_txt_xform = pt_fcn;
714       m.typeinfo = &type;
715       m.raw_user_name = name;
716       m.pod_size = pod_size;
717       m.username = username_map.end();
718       rebuild_usernames = true;
719       return 0;
720    }
721    else
722    {
723       MappingFunctions &original = functions[ans.first->second];
724       // Should we just check the user-defined name?
725       if ( ( original.init == i_fcn ) &&
726            ( original.transform == t_fcn ) &&
727            ( original.pod_transform == p_fcn ) &&
728            ( original.pod_txt_xform == pt_fcn ))
729       {
730          // A duplicate registration pointing to the same functions...
731          return 0;
732       }
733       cerr << "WARNING: Serialization_Manager::register_serializer(): "
734          " discarding duplicate registration for '" << mangledName(type) <<
735          "'" << endl;
736       return error::Serialization::DuplicateRegistration;
737    }
738 }
739 
740 
741 void
rebuild_user_name_map()742 Serialization_Manager::rebuild_user_name_map()
743 {
744    // clear out everything
745    username_map.clear();
746    username_map_t::iterator noUserName = username_map.end();
747 
748    vector<MappingFunctions>::iterator it = functions.begin();
749    vector<MappingFunctions>::iterator itEnd = functions.end();
750    for( ; it != itEnd; ++it )
751       it->username = noUserName;
752 
753    // rebuild everything
754    typename_map_t::iterator t_it = typename_map.begin();
755    typename_map_t::iterator t_itEnd = typename_map.end();
756    for( ; t_it != t_itEnd; ++t_it )
757       resolve_user_name(t_it->first);
758 
759    rebuild_usernames = false;
760 }
761 
762 
763 std::string
resolve_user_name(std::string mangled)764 Serialization_Manager::resolve_user_name(std::string mangled)
765 {
766    typename_map_t::iterator mangled_it = typename_map.find(mangled);
767    // unknown mangled type name...
768    if ( mangled_it == typename_map.end() )
769       return "*";
770 
771    MappingFunctions &m = functions[mangled_it->second];
772 
773    // this user name has already been fully resolved
774    if ( m.username != username_map.end() )
775       return m.username->first;
776 
777    // we must resolve the name
778    string uname = "";
779    size_t sep = m.raw_user_name.find(template_separator);
780    uname = m.raw_user_name.substr(0, sep);
781    if ( sep != string::npos )
782    {
783       // This uname is a template (defined in terms of mangled type names)
784       uname += "<";
785       while ( sep != string::npos )
786       {
787          ++sep;
788          size_t next_sep = m.raw_user_name.find(template_separator, sep);
789          uname += resolve_user_name(m.raw_user_name.substr(sep,
790                                                            next_sep-sep));
791          uname += ',';
792          sep = next_sep;
793       }
794       *uname.rbegin() = '>';
795    }
796 
797    // insert the newly-resolved name...
798    pair<username_map_t::iterator, bool> ans
799       = username_map.insert(username_pair_t(uname, mangled_it));
800    if ( ans.second )
801       m.username = ans.first;
802    else
803    {
804       cerr << "WARNING: Serialization_Manager::resolve_user_name(): \n"
805 "     Multiple mangled type names map to the same user-defined name.  It is\n"
806 "     likely that you forgot to register a name or a serialization function\n"
807 "     for a template argument.  If you attempt to serialize either type,\n"
808 "     you will get an exception.\n"
809 "  User name: " << uname << endl
810             << "  Mangled: " << mangled << endl
811             << "           " << username_map[uname]->first << endl;
812 
813       m.username = username_map.end();
814       if ( ans.first->second != typename_map.end() )
815       {
816          functions[ans.first->second->second].username = username_map.end();
817          ans.first->second = typename_map.end();
818       }
819    }
820 
821    return uname;
822 }
823 
824 
825 } // namespace utilib
826