various fixes made when working with older gcc 3.2.3
[dyninst.git] / dynutil / h / Annotatable.h
1 /*
2  * Copyright (c) 1996-2004 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #ifndef __ANNOTATABLE_H__
43 #define __ANNOTATABLE_H__
44
45 #include <vector>
46 #include <map>
47 #include <typeinfo>
48 #include <string>
49 #include <assert.h>
50 #include <stdlib.h>
51 #include "dyntypes.h"
52
53
54 namespace Dyninst
55 {
56
57 typedef short AnnotationClassID;
58 typedef bool (*anno_cmp_func_t)(void *, void*);
59
60 // since can't have a single static in a temlated class that spans all template instances.
61 //extern int AnnotationClass_nextId;
62
63 extern int newAnnotationClass();
64 extern bool void_ptr_cmp_func(void *, void *);
65
66 class SerializerBase;
67
68 class AnnotationClassBase
69 {
70    private:
71       static std::vector<AnnotationClassBase *> annotation_types;
72       anno_cmp_func_t cmp_func;
73       AnnotationClassID id;
74
75    protected:
76       AnnotationClassBase(anno_cmp_func_t cmp_func_ = NULL);
77
78    public:
79
80       static AnnotationClassBase *findAnnotationClass(unsigned int id);
81
82       anno_cmp_func_t getCmpFunc()
83       {
84          return cmp_func;
85       }
86
87       AnnotationClassID getID() { return id; }
88 };
89
90 template <class T> 
91 class AnnotationClass : public AnnotationClassBase {
92    public:
93       typedef bool (*ser_func_t) (SerializerBase &, T &);
94       // typedef T annotation_realtype;
95
96       AnnotationClass(std::string n, 
97             anno_cmp_func_t cmp_func_ = NULL, 
98             bool (*serializer)(SerializerBase &, T&) = NULL) :
99          AnnotationClassBase(cmp_func_),
100          name(n),
101          serialize_func(serializer)
102       {}
103
104       std::string &getName() {return name;}
105
106       ser_func_t getSerializeFunc()
107       {
108          return serialize_func;
109       }
110
111
112    private:
113       std::string name;
114       ser_func_t serialize_func;
115 };
116
117 typedef void *anno_list_t;
118
119 class AnnotatableDense
120 {
121    /**
122     * Inheriting from this class adds a pointer to each object.  Multiple
123     * types of annotations are stored under this pointer in a 
124     * annotation_type -> anno_list_t map.
125     **/
126
127    private:
128
129       typedef anno_list_t anno_map_t;
130
131       struct aInfo {
132          anno_map_t *data;
133          int max;
134       };
135
136       aInfo *annotations;
137
138    public:
139       AnnotatableDense() : annotations(NULL)
140       {
141       }
142
143       template<class T> 
144       bool addAnnotation(T *a, AnnotationClass<T> &a_id) 
145       {
146          int size;
147          int id = a_id.getID();
148
149          if (!annotations) 
150          {
151             size = id;
152             annotations = (aInfo *) malloc(sizeof(aInfo));
153
154             annotations->data = (anno_list_t *) calloc(sizeof(anno_list_t *), size);
155             annotations->max = size;
156          } 
157          else if (id > annotations->max) 
158          {
159             size = annotations->max * 2;
160             annotations->max = size;
161             annotations->data = (anno_list_t *) realloc(annotations->data, sizeof(anno_list_t *) * size);
162          }
163
164          annotations->data[id] = (void *) a;
165
166          return true;
167       }
168
169       template<class T> 
170       bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const
171       {
172          if (!annotations)
173             return false;
174
175          int id = a_id.getID();
176
177          if (id > annotations->max) 
178          {
179             return false;
180          }
181
182          a = (T *) annotations->data[id];
183          if (!a) return false;
184
185          return true;
186       }
187
188       template<class T> 
189       bool removeAnnotation(AnnotationClass<T> &a_id)
190       {
191          if (!annotations) return false;
192
193          int id = a_id.getID();
194          if (id > annotations->max) 
195          {
196             return false;
197          }
198
199          if (!annotations->data[id]) 
200             return false;
201
202          annotations->data[id] = NULL;
203
204          return true;
205       }
206
207 };
208
209 class AnnotatableSparse
210 {
211    public:
212       struct void_ptr_hasher
213       {
214          size_t operator()(const void* a) const
215          {
216             return (size_t) a;
217          }
218       };
219
220 #if defined (os_windows)
221       typedef dyn_hash_map<void *, void *> annos_by_type_t;
222 #else
223       typedef dyn_hash_map<void *, void *, void_ptr_hasher> annos_by_type_t;
224 #endif
225
226       typedef std::vector<annos_by_type_t *> annos_t;
227
228    private:
229
230       static annos_t annos;
231
232       template <class T>
233       annos_by_type_t *getAnnosOfType(AnnotationClass<T> &a_id, bool do_create =false) const
234       {
235          int aid = a_id.getID();
236
237          long nelems_to_create = aid - annos.size() + 1;
238
239          if (nelems_to_create > 0)
240          {
241             if (!do_create)
242             {
243                return NULL;
244             }
245
246             while (nelems_to_create)
247             {
248                annos_by_type_t *newl = new annos_by_type_t();
249                annos.push_back(newl);
250                nelems_to_create--;
251             }
252          }
253
254          annos_by_type_t *abt = annos[aid];
255
256          return abt;
257       }
258
259       void *getAnnosForObject(annos_by_type_t *abt,
260             void *obj, bool do_create = false) const 
261       {
262          assert(abt);
263          assert(obj);
264
265          void  *target = NULL;
266
267          annos_by_type_t::iterator iter = abt->find(obj);
268
269          if (iter == abt->end())
270          {
271             if (!do_create)
272             {
273                return NULL;
274             }
275
276             (*abt)[obj] = target;
277          }
278          else
279          {
280             target = iter->second;
281          }
282
283          return target;
284       }
285
286    public:
287       bool operator==(AnnotatableSparse &cmp)
288       {
289          unsigned this_ntypes = annos.size();
290          unsigned cmp_ntypes = cmp.annos.size();
291          unsigned ntypes = (cmp_ntypes > this_ntypes) ? cmp_ntypes : this_ntypes;
292
293          for (unsigned int i = 0; i < ntypes; ++i) 
294          {
295             if ((i >= cmp_ntypes) || (i >= this_ntypes)) 
296             {
297                //  compare is done since at least one set of annotations
298                //  has been exhausted
299                break;
300             }
301
302             annos_by_type_t *this_abt = annos[i];
303             annos_by_type_t *cmp_abt = cmp.annos[i];
304
305             if (!this_abt) 
306             {
307                fprintf(stderr, "%s[%d]:  WEIRD: FIXME\n", FILE__, __LINE__);
308                continue;
309             }
310
311             if (!cmp_abt) 
312             {
313                fprintf(stderr, "%s[%d]:  WEIRD: FIXME\n", FILE__, __LINE__);
314                continue;
315             }
316
317             annos_by_type_t::iterator this_abt_iter = this_abt->find(this);
318             annos_by_type_t::iterator cmp_abt_iter = cmp_abt->find(&cmp);
319
320             //  if one has annotations of this particular type and other other
321             //  doesn't, then we are def. not equal, so fail:
322
323             if (this_abt_iter == this_abt->end())
324             {
325                if (cmp_abt_iter != cmp_abt->end())
326                {
327                   return false;
328                }
329
330                //  both are at end()
331                continue;
332             }
333
334             if (   (cmp_abt_iter == cmp_abt->end())
335                   && (this_abt_iter != this_abt->end()))
336             {
337                return false;
338             }
339
340             AnnotationClassBase *acb = AnnotationClassBase::findAnnotationClass(i);
341
342             if (!acb)
343             {
344                fprintf(stderr, "%s[%d]:  cannot find annotation class for id %d\n", 
345                      FILE__, __LINE__, i);
346                return false;
347             }
348
349             //  both have annotation -- do the compare
350             anno_cmp_func_t cmpfunc = acb->getCmpFunc();
351
352             if (!cmpfunc)
353             {
354                //  even if not explicitly specified, a default pointer-compare
355                //  function should be returned here.
356
357                fprintf(stderr, "%s[%d]:  no cmp func for anno id %d\n", 
358                      FILE__, __LINE__, i);
359                return false;
360             }
361
362             void *arg1 = cmp_abt_iter->second;
363             void *arg2 = this_abt_iter->second;
364
365             bool ret = (*cmpfunc)(arg1, arg2);
366
367             return ret;
368          }
369
370          return true;
371       }
372
373       template<class T>
374       bool addAnnotation(T *a, AnnotationClass<T> &a_id)
375          {
376             void *obj = this;
377             annos_by_type_t *abt = getAnnosOfType(a_id, true /*do create if needed*/);
378             assert(abt);
379
380             annos_by_type_t::iterator iter = abt->find(obj);
381             if (iter == abt->end())
382             {
383                (*abt)[obj] = (void *)a;
384             }
385             else
386             {
387                //  if the annotation already exists and is identical (by pointer, of course)
388                //  what is the best solution?  Replacement makes no sense, since it is the
389                //  same.  The question is -- do we fail and report this situation as a logic
390                //  error?  This is probably the most conservative and hence safest approach,
391                //  but, since the pointer is identical, let's play nice and just report 
392                //  success?
393
394                return true;
395
396                //  maybe want to do (silent) replace here?
397                //fprintf(stderr, "%s[%d]:  failing to add already existing annotation here\n", FILE__, __LINE__);
398                //return false;
399
400             }
401
402             return true;
403          }
404
405       template<class T>
406       bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const 
407       {
408          a = NULL;
409
410          annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
411
412          if (!abt)
413          {
414             //fprintf(stderr, "%s[%d]:  no annotations of type %s\n",
415             //      FILE__, __LINE__, a_id.getName().c_str());
416             return false;
417          }
418
419          AnnotatableSparse * this_noconst = const_cast<AnnotatableSparse *>(this);
420          void *annos_for_object = getAnnosForObject(abt, (void *)this_noconst,
421                false /*no create if none*/);
422
423          if (!annos_for_object)
424          {
425             //fprintf(stderr, "%s[%d]:  no annotations of type %s\n", 
426             //      FILE__, __LINE__, a_id->getName().c_str());
427             return false;
428          }
429
430          a = (T *)annos_for_object;
431          return true;
432       }
433
434 #if 0
435       template<class T>
436          bool clearAnnotationsOfType(AnnotationClass<T> &a_id)
437          {
438             annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
439
440             if (!abt)
441             {
442                return false;
443             }
444
445             int nelem_cleared = abt->size();
446             abt->clear();
447
448             return (nelem_cleared != 0);
449          }
450 #endif
451
452       template<class T>
453       bool removeAnnotation(AnnotationClass<T> &a_id)
454       {
455          int aid = a_id.getID();
456
457          if (aid >= annos.size()) 
458          {
459             fprintf(stderr, "%s[%d]:  failed to remove nonexistant annotation\n", 
460                     __FILE__, __LINE__);
461             return false;
462          }
463
464          annos_t::iterator a_iter(aid);
465          annos.erase(a_iter);
466          //annos.erase(aid);
467
468 #if 0
469          int nelems_to_create = aid - annos.size() + 1;
470
471          if (nelems_to_create > 0)
472          {
473             if (!do_create)
474             {
475                return NULL;
476             }
477
478             while (nelems_to_create)
479             {
480                annos_by_type_t *newl = new annos_by_type_t();
481                annos.push_back(newl);
482                nelems_to_create--;
483             }
484          }
485
486          annos_by_type_t *abt = annos[aid];
487          annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
488
489          if (!abt)
490          {
491             return false;
492          }
493
494          annos_by_type_t::iterator iter = abt->find(obj);
495          if (iter == abt->end())
496          {
497             fprintf(stderr, "%s[%d]:  failing to remove already nonexistant annotation here\n", FILE__, __LINE__);
498             return false;
499          }
500          else
501          {
502             abt->erase(iter);
503          }
504
505 #endif
506          return true;
507       }
508
509 };
510
511 //AnnotatableSparse::annos_t AnnotatableSparse::annos;
512 } // namespace
513
514 #endif