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