initial (and partial) fleshing out of symtab serialization test
[dyninst.git] / dynutil / h / Serialization.h
1
2 #if !defined (SERIALIZATION_PUBLIC_H)
3 #define SERIALIZATION_PUBLIC_H
4 //  Hopefully just a few definitions allowing for a public interface to 
5 //  serializing user-providede annotations
6
7 #include <stdio.h>
8 #include <assert.h>
9 #include <stdexcept>
10 #include <typeinfo>
11 #include <vector>
12 #include <assert.h>
13 #include "dyntypes.h"
14 #include "util.h"
15
16 namespace Dyninst {
17 //  SER_ERR("msg") -- an attempt at "graceful" failure.  If debug flag is set
18 //  it will assert, otherwise it throws...  leaving the "graceful" aspect
19 //  to the next (hopefully top-level) exception handler.
20
21
22 COMMON_EXPORT bool &serializer_debug_flag();
23
24 #define SER_ERR(cmsg) \
25    do { \
26       if (serializer_debug_flag()) { \
27          fprintf(stderr, "%s", cmsg); \
28          assert (0); \
29       } else { \
30          throw SerializerError(__FILE__, __LINE__, std::string(cmsg)); \
31       } \
32    } while (0)
33
34
35 class SerializerBase;
36
37
38 typedef enum {sd_serialize, sd_deserialize} iomode_t;
39 typedef bool (*deserialize_and_annotate_t)(SerializerBase *, void *parent);
40
41 bool addDeserializeFuncForType(deserialize_and_annotate_t, const std::type_info *);
42 deserialize_and_annotate_t getDeserializeFuncForType(const std::type_info *);
43
44 class COMMON_EXPORT Serializable {
45    protected:
46       Serializable() {}
47       virtual ~Serializable() {}
48
49    public:
50       virtual void serialize(SerializerBase *,  const char * = NULL) = 0;
51 };
52
53 class SerializerError : public std::runtime_error {
54    //  SerializerError:  a small class that is thrown by serialization/deserialization
55    //  routines.  This exists as an attempt to standardize and simplify error handling
56    //  for ser-des routines that are possibly deeply nested.
57    //  Here's the rub:  we don't want stray, unhandled exceptions finding their way into
58    //  the larger system...  thus all entry points to serialization/deserialization need
59    //  to catch this exception to render it transparent to the rest of the system.
60
61    public:
62
63    typedef enum {
64       ser_err_unspecified,
65       ser_err_no_err,
66       ser_err_disabled
67    } SerializerErrorType;
68
69    private:
70
71    std::string file__;
72    int line__;
73    SerializerErrorType err__;
74
75    public:
76
77
78    SerializerError(const std::string &__file__, 
79          const int &__line__, 
80          const std::string &msg, 
81          SerializerErrorType __err__ = ser_err_unspecified) :
82       runtime_error(msg),
83       file__(__file__),
84       line__(__line__),
85       err__(__err__)
86    {}
87
88    virtual ~SerializerError() throw() {}
89
90    std::string file() const {return file__;}
91    int line() const {return line__;}
92    SerializerErrorType code() const {return err__;}
93 };
94
95
96 COMMON_EXPORT void printSerErr(const SerializerError &err);
97
98 template <class S, class T>
99 void translate_vector(S *ser, std::vector<T> &vec,
100       const char *tag = NULL, const char *elem_tag = NULL)
101 {
102    unsigned int nelem = vec.size();
103    ser->vector_start(nelem, tag);
104
105    if (ser->iomode() == sd_deserialize) 
106    {
107       if (vec.size())
108          SER_ERR("nonempty vector used to create");
109
110       //  zero size vectors are allowed
111       //  what it T is a complex type (with inheritance info)??
112       //  does resize() call default ctors, or should we do that
113       //  manually here? look this up.
114       if (nelem)
115          vec.resize(nelem);
116    }
117
118    for (unsigned int i = 0; i < vec.size(); ++i) 
119    {
120       T &t = vec[i];
121       gtranslate(ser, t, elem_tag);
122    }
123
124    ser->vector_end();
125 }
126
127
128 template <class S, class T>
129 void translate_vector(S *ser, std::vector<T *> &vec, 
130       const char *tag = NULL, const char *elem_tag = NULL) 
131 {
132    unsigned int nelem = vec.size();
133    ser->vector_start(nelem, tag);
134
135    if (ser->iomode() == sd_deserialize) 
136    {
137       if (vec.size()) 
138          SER_ERR("nonempty vector used to create");
139
140       //  zero size vectors are allowed
141       if (nelem) 
142       {
143          //  block-allocate array of underlying type, then assign to our vector
144          //  What happens if an individual elem is later deleted??
145          T *chunk_alloc = new T[nelem];
146          vec.resize(nelem);
147          for (unsigned int i = 0; i < nelem; ++i)
148             vec[i] = &(chunk_alloc[i]);
149       }
150    }
151
152    for (unsigned int i = 0; i < vec.size(); ++i) 
153    {
154       T &t = *(vec[i]);
155       gtranslate(ser, t, elem_tag);
156    }
157
158    ser->vector_end();
159 }
160
161 template <class S, class T>
162 void translate_vector(S *ser, std::vector<std::vector<T> > &vec, 
163       const char *tag = NULL, const char *elem_tag = NULL) 
164 {
165    fprintf(stderr, "%s[%d]:  welcome to translate vector of vectors\n", 
166            __FILE__, __LINE__);
167
168    unsigned int nelem = vec.size();
169    ser->vector_start(nelem, tag);
170    if (ser->iomode() == sd_deserialize) 
171    {
172       if (vec.size())
173          SER_ERR("nonempty vector used to create");
174
175       //  zero size vectors are allowed
176       //  what it T is a complex type (with inheritance info)??
177       //  does resize() call default ctors, or should we do that
178       //  manually here? look this up.
179       if (nelem)
180          vec.resize(nelem);
181    }
182
183    for (unsigned int i = 0; i < vec.size(); ++i) 
184    {
185       std::vector<T> &tv = vec[i];
186       translate_vector(ser,tv, tag, elem_tag);
187    }
188
189    ser->vector_end();
190 }
191
192 template <class S, class K, class V>
193 void translate_hash_map(S *ser, dyn_hash_map<K, V> &hash, 
194       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
195 {   
196    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s>()\n", 
197            __FILE__, __LINE__,
198            typeid(K).name(), typeid(V).name()); 
199
200    unsigned int nelem = hash.size();
201    ser->hash_map_start(nelem, tag);
202    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
203            __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de"); 
204
205    if (ser->iomode() == sd_serialize) 
206    {
207       typename dyn_hash_map<K,V>::iterator iter = hash.begin();
208       fprintf(stderr, "%s[%d]:  about to serialize hash with %d elements\n", 
209               __FILE__, __LINE__, hash.size());
210
211       while (iter != hash.end()) 
212       {
213          K k = iter->first;
214          V v = iter->second;
215          ser->translate_base(k, key_tag);
216          ser->translate_base(v, value_tag);
217          iter++;           
218       }
219    }
220    else 
221    {
222       //  can we do some kind of preallocation here?
223       for (unsigned int i = 0; i < nelem; ++i) 
224       {
225          K k;
226          V v;
227          ser->translate_base(k, key_tag);
228          ser->translate_base(v, value_tag);
229          hash[k] = v;
230       }
231    }
232
233    ser->hash_map_end();
234 }
235
236 template <class S, class K, class V>
237 void translate_hash_map(S *ser, dyn_hash_map<K, V *> &hash,
238       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
239 {
240    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s*>()\n", 
241          __FILE__, __LINE__,
242          typeid(K).name(), typeid(V).name());
243
244    unsigned int nelem = hash.size();
245    ser->hash_map_start(nelem, tag);
246
247    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
248          __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de");
249
250    if (ser->iomode() == sd_serialize) 
251    {
252       typename dyn_hash_map<K,V *>::iterator iter = hash.begin();
253
254       while (iter != hash.end()) 
255       {
256          K k = iter->first;
257          V *v = iter->second;
258          ser->translate_base(k, key_tag);
259          ser->translate_base(*v, value_tag);
260          iter++;
261       }
262    }
263    else 
264    {
265       //  can we do some kind of preallocation here?
266       for (unsigned int i = 0; i < nelem; ++i) 
267       {
268          K k;
269          V *v = new V();
270          ser->translate_base(k, key_tag);
271          ser->translate_base(*v, value_tag);
272          hash[k] = v;
273       }
274    }
275    ser->hash_map_end();
276 }
277
278 template <class S, class K, class V>
279 void translate_hash_map(S *ser, dyn_hash_map<K, char *> &hash,
280       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
281 {
282    //  THIS SPECIALIZATION DOES NOT WORK CORRECTLY (YET)
283    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s*>()\n", 
284          __FILE__, __LINE__,
285          typeid(K).name(), typeid(V).name());
286
287    unsigned int nelem = hash.size();
288    ser->hash_map_start(nelem, tag);
289
290    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
291          __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de");
292
293    if (ser->iomode() == sd_serialize) 
294    {
295       typename dyn_hash_map<K,V *>::iterator iter = hash.begin();
296       
297       while (iter != hash.end()) 
298       {
299          K k = iter->first;
300          V v = iter->second;
301          ser->translate_base(k, key_tag);
302          ser->translate_base(v, value_tag);
303          iter++;
304       }
305    }
306    else 
307    {
308       //  can we do some kind of preallocation here?
309       for (unsigned int i = 0; i < nelem; ++i) 
310       {
311          K k;
312          V v;
313          ser->translate_base(k, key_tag);
314          ser->translate_base(*v, value_tag);
315          hash[k] = v;
316       }
317    }
318    ser->hash_map_end();
319 }
320
321
322 COMMON_EXPORT void trans_adapt(SerializerBase *ser, Serializable &it,  const char *tag);
323 COMMON_EXPORT void trans_adapt(SerializerBase *ser, Serializable *itp,  const char *tag);
324
325 COMMON_EXPORT void trans_adapt(SerializerBase *ser, bool &it,  const char *tag);
326 COMMON_EXPORT void trans_adapt(SerializerBase *ser, int &it,  const char *tag);
327 COMMON_EXPORT void trans_adapt(SerializerBase *ser, unsigned int &it,  const char *tag);
328 COMMON_EXPORT void trans_adapt(SerializerBase *ser, long &it,  const char *tag);
329 COMMON_EXPORT void trans_adapt(SerializerBase *ser, unsigned long &it,  const char *tag);
330 COMMON_EXPORT void trans_adapt(SerializerBase *ser, char &it,  const char *tag);
331 COMMON_EXPORT void trans_adapt(SerializerBase *ser, char *&it,  const char *tag);
332 COMMON_EXPORT void trans_adapt(SerializerBase *ser, std::string &it,  const char *tag);
333 COMMON_EXPORT void trans_adapt(SerializerBase *ser, float &it,  const char *tag);
334 COMMON_EXPORT void trans_adapt(SerializerBase *ser, double &it,  const char *tag);
335
336 COMMON_EXPORT bool isBinary(Dyninst::SerializerBase *ser);
337 COMMON_EXPORT bool isOutput(Dyninst::SerializerBase *ser);
338
339 typedef void NOTYPE_T;
340 template<class S, class T, class T2 = NOTYPE_T>
341 class trans_adaptor {
342    public:
343       trans_adaptor() 
344       {
345          fprintf(stderr, "%s[%d]:  trans_adaptor  -- general\n", __FILE__, __LINE__);
346       } 
347
348       T * operator()(S *ser, T & it, const char *tag = NULL, const char * /*tag2*/ = NULL)
349       {
350          trans_adapt(ser, it, tag);
351          return &it;
352       }
353 };
354
355 template<class S, class T2>
356 class trans_adaptor<S, Serializable, T2> {
357    public:
358       trans_adaptor() 
359       {
360          fprintf(stderr, "%s[%d]:  trans_adaptor  -- general\n", __FILE__, __LINE__);
361       } 
362
363       Serializable * operator()(S *ser, Serializable & it, const char *tag = NULL, 
364             const char * /*tag2*/ = NULL)
365       {
366          gtranslate(ser, it, tag);
367          return &it;
368       }
369 };
370
371 template<class S, class T, class TT2>
372 class trans_adaptor<S, std::vector<T>, TT2 > {
373    public:
374       trans_adaptor()
375       {
376          fprintf(stderr, "%s[%d]:  trans_adaptor  -- vectorl\n", __FILE__, __LINE__);
377       }
378
379       std::vector<T> * operator()(S *ser, std::vector<T> &v, const char *tag = NULL, 
380             const char *tag2 = NULL) 
381       {
382          translate_vector(ser, v, tag, tag2);         //  maybe catch errors here?
383          return &v;
384       }
385 };
386
387 template<class S, class T, class TT2>
388 class trans_adaptor<S, std::vector<T *>, TT2>  {
389    public: 
390       trans_adaptor() 
391       {
392          fprintf(stderr, "%s[%d]:  trans_adaptor  -- vector of ptrs\n", __FILE__, __LINE__);
393       }
394
395       std::vector<T*> * operator()(S *ser, std::vector<T *> &v, const char *tag = NULL, 
396             const char *tag2 = NULL) 
397       {
398          translate_vector(ser, v, tag, tag2);
399          //  maybe catch errors here?
400          return &v;
401       }
402 };
403
404 #if 0
405 template<class T, class ANNO_NAME, bool, annotation_implementation_t>
406 class Annotatable<T, ANNO_NAME,bool, annotation_implementation_t>;
407 #endif
408    
409 #if 0
410 I really really wish this worked, maybe it still can given some more pounding
411
412 template<class S, class T, class ANNO_NAME, bool SERIALIZABLE, annotation_implementation_t IMPL>
413 class trans_adaptor<S, 
414       Annotatable<T, 
415       ANNO_NAME, 
416       SERIALIZABLE,
417       IMPL> &>  {
418    public: 
419       trans_adaptor() 
420       {
421          fprintf(stderr, "%s[%d]:  trans_adaptor  -- annotatable<%s, %s, %s>\n", 
422                __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
423                SERIALIZABLE ? "true" : "false");
424       }
425
426       Annotatable<T, ANNO_NAME, SERIALIZABLE, IMPL> * operator()(S *ser, 
427             Annotatable<T, ANNO_NAME, SERIALIZABLE, IMPL> &v, const char *tag = NULL, 
428             const char *tag2 = NULL) 
429       {
430           if (!SERIALIZABLE) 
431           {
432              fprintf(stderr, "%s[%d]:  Annotatable<%s, %s, %s>, not serializable\n", 
433                    __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
434                    SERIALIZABLE ? "true" : "false");
435              return NULL;
436           }
437
438           int nelem = v.size();
439
440           if (0 == nelem) 
441           {
442              fprintf(stderr, "%s[%d]:  Annotatable<%s, %s, %s>, no annotations\n", 
443                    __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
444                    SERIALIZABLE ? "true" : "false");
445              return NULL;
446           }
447
448           //  data structure must exist since size > 0
449
450           std::vector<T> &anno_vec = v.getDataStructure();
451
452           //  But is this OK??  (This goes around the usual annotations interface)
453           //  probably not, but let's see if it works anyways
454
455           fprintf(stderr, "%s[%d]:  WARNING:  This may not be kosher -- circumventing the anotations interface, think on this\n", __FILE__, __LINE__);
456           translate_vector(ser, anno_vec, tag, tag2);
457
458          //  maybe catch errors here?
459          return &v;
460       }
461 };
462 #endif
463
464 template <class S, class T>
465 void gtranslate(S *ser, T &it, const char *tag = NULL, const char *tag2 = NULL)
466 {
467    fprintf(stderr, "%s[%d]:  welcome to gtranslate<%s, %s>(%p)\n",
468          __FILE__, __LINE__,
469          "SerializerBase",
470          typeid(T).name(), &it);
471
472    //  Maybe just need to do try/catch here since the template mapping may 
473    //  change the type of return value thru template specialization
474
475    trans_adaptor<S, T> ta;
476    fprintf(stderr, "%s[%d]: gtranslate: before operation\n", __FILE__, __LINE__);
477
478    T *itp = ta(ser, it, tag, tag2);
479
480    if (!itp) 
481    {
482       fprintf(stderr, "%s[%d]: translate adaptor failed to de/serialize\n", 
483             __FILE__, __LINE__);
484    }
485 }
486
487 COMMON_EXPORT bool ifxml_start_element(SerializerBase *sb, const char *tag);
488 COMMON_EXPORT bool ifxml_end_element(SerializerBase *sb, const char * /*tag*/);
489
490 //template<class T> class SerializerBin<T>;
491 //template<class T> class SerializerXML<T>;
492
493 COMMON_EXPORT bool sb_is_input(SerializerBase *sb);
494 COMMON_EXPORT bool sb_is_output(SerializerBase *sb);
495
496 #if 0
497 template <class T>
498 bool ifinput(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
499 {
500    if (!sb_is_input(sb))
501       return false;
502
503
504    return (*f)(sb, itp);
505 }
506
507 template <class T>
508 bool ifoutput(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
509 {
510    if (!sb_is_output(sb))
511       return false;
512
513    return (*f)(sb, itp);
514 }
515
516 template <class T>
517 bool ifbin(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
518 {
519    SerializerBin *sbin = dynamic_cast<SerializerBin *>(sb);
520
521    if (!sbin)
522       return false;
523
524    return (*f)(sbin, itp);
525 }
526
527 template <class T>
528 bool ifxml(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
529 {
530    SerializerXML *sxml = dynamic_cast<SerializerXML *>(sb);
531
532    if (!sxml)
533       return false;
534
535    return (*f)(sxml, itp);
536 }
537 #endif
538 #if 0
539 {
540    fprintf(stderr, "%s[%d]:  welcome to gtranslate<%s, %s>(%p)\n",
541          __FILE__, __LINE__,
542          "SerializerBase",
543          typeid(TT).name(), &it);
544
545    //  Maybe just need to do try/catch here since the template mapping may 
546    //  change the type of return value thru template specialization
547    assert(use_func);
548    (*use_func)(ser, it);
549 }
550
551 template<class S, class TT>
552 void trans_enum(S *ser, TT &it, std::vector<std::string> *enum_tags_ptr) 
553 {
554    assert(enum_tags_ptr);
555    std::vector<std::string> &enum_tags = *enum_tags_ptr;
556    assert(it < enum_tags.size());
557    unsigned int enum_int = (unsigned int) it;
558    gtranslate(ser, it);
559 }
560 #endif
561
562
563 template <class S, class T>
564 void gtranslate(S *ser, 
565       T &it, 
566       const char * (*to_str_func)(T), 
567       const char *tag = NULL, 
568       const char * /*tag2*/ = NULL)
569 {
570    assert(ser);
571    int enum_int = (int) it;
572
573    if (!isBinary(ser)) 
574    {
575       assert(isOutput(ser));
576
577       // use human-readable tag
578       const char *enum_tag = (*to_str_func)(it);
579       std::string enum_tag_str(enum_tag);
580       assert(enum_tag);
581
582       gtranslate(ser, enum_tag_str, tag, NULL);
583    }
584    else 
585    {
586       //  just in/output raw binary value 
587       gtranslate(ser, enum_int, tag, NULL);
588       it = (T) enum_int;
589    }
590 }
591
592 class SerializerError;
593
594 template <class S, class T>
595 bool gtranslate_w_err(S *ser, T&it, const char *tag = NULL, const char *tag2 = NULL)
596 {
597
598    try 
599    {
600       gtranslate(ser, it, tag, tag2);
601    }
602
603    catch (const SerializerError &err_) 
604    {
605       fprintf(stderr, "%s[%d]:  gtranslate failed\n", __FILE__, __LINE__);
606       printSerErr(err_);
607       return false;
608    }
609    return true;
610 }
611
612 //  These are for testing purposes -- do not use elsewhere
613 //  Must deallocate serializer that is returned when done.
614 #if 0
615 SerializerBase *nonpublic_make_bin_serializer(std::string file);
616 SerializerBase *nonpublic_make_bin_deserializer(std::string file);
617 void nonpublic_free_bin_serializer(SerializerBase *sb);
618 #endif
619 #if 0
620 template <class T> class SerializerBin;
621
622 template <class T>
623 inline SerializerBase *nonpublic_make_bin_serializer(T *t, std::string file)
624 {
625         SerializerBin<T> *ser;
626         ser = new SerializerBin<T>(t, "SerializerBin", file, sd_serialize, true);
627         return ser;
628 }
629
630 template <class T>
631 inline void nonpublic_free_bin_serializer(SerializerBase *sb)
632 {
633         SerializerBin<T> *sbin = dynamic_cast<SerializerBin<T> *>(sb);
634         if (sbin)
635         {
636                 delete(sbin);
637         }
638         else
639                 fprintf(stderr, "%s[%d]:  FIXME\n", FILE__, __LINE__);
640 }
641
642 template <class T>
643 inline SerializerBase *nonpublic_make_bin_deserializer(T *t,std::string file)
644 {
645         SerializerBin<T> *ser;
646         ser = new SerializerBin<T>(t, "DeserializerBin", file, sd_deserialize, true);
647         return ser;
648 }
649 #endif
650
651 } /* namespace Dyninst */
652 #endif