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