Windows test suite & build fixes. VC2003 and VC2008 should both now build. Known...
[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 <string.h> // for strrchr()
50 #include <assert.h>
51 #include <stdlib.h>
52 #include "dyntypes.h"
53 #include "util.h"
54
55 namespace Dyninst
56 {
57
58 typedef short AnnotationClassID;
59 typedef bool (*anno_cmp_func_t)(void *, void*);
60
61 // since can't have a single static in a temlated class that spans all template instances.
62 //COMMON_EXPORT extern int AnnotationClass_nextId;
63
64 extern int newAnnotationClass();
65 extern bool void_ptr_cmp_func(void *, void *);
66
67 class SerializerBase;
68
69 class AnnotationClassBase
70 {
71    private:
72       static std::vector<AnnotationClassBase *> *annotation_types;
73       anno_cmp_func_t cmp_func;
74       AnnotationClassID id;
75
76    protected:
77       COMMON_TEMPLATE_EXPORT AnnotationClassBase(anno_cmp_func_t cmp_func_ = NULL);
78
79    public:
80
81       static AnnotationClassBase *findAnnotationClass(unsigned int id);
82
83       anno_cmp_func_t getCmpFunc()
84       {
85          return cmp_func;
86       }
87
88       AnnotationClassID getID() { return id; }
89 };
90
91 template <class T> 
92 class AnnotationClass : public AnnotationClassBase {
93    public:
94       typedef bool (*ser_func_t) (SerializerBase &, T &);
95       // typedef T annotation_realtype;
96
97       COMMON_TEMPLATE_EXPORT AnnotationClass(std::string n, 
98             anno_cmp_func_t cmp_func_ = NULL, 
99             bool (*serializer)(SerializerBase &, T&) = NULL) :
100          AnnotationClassBase(cmp_func_),
101          name(n),
102          serialize_func(serializer)
103       {}
104
105       std::string &getName() {return name;}
106
107       ser_func_t getSerializeFunc()
108       {
109          return serialize_func;
110       }
111
112
113    private:
114       std::string name;
115       ser_func_t serialize_func;
116 };
117
118 typedef void *anno_list_t;
119
120 class AnnotatableDense
121 {
122    /**
123     * Inheriting from this class adds a pointer to each object.  Multiple
124     * types of annotations are stored under this pointer in a 
125     * annotation_type -> anno_list_t map.
126     **/
127
128    private:
129
130       typedef anno_list_t anno_map_t;
131
132       struct aInfo {
133          anno_map_t *data;
134          int max;
135       };
136
137       aInfo *annotations;
138
139    public:
140       AnnotatableDense() : annotations(NULL)
141       {
142       }
143
144       template<class T> 
145       bool addAnnotation(T *a, AnnotationClass<T> &a_id) 
146       {
147          int size;
148          int id = a_id.getID();
149
150          if (!annotations) 
151          {
152             size = id;
153             annotations = (aInfo *) malloc(sizeof(aInfo));
154
155             annotations->data = (anno_list_t *) calloc(sizeof(anno_list_t *), size);
156             annotations->max = size;
157          } 
158          else if (id > annotations->max) 
159          {
160             size = annotations->max * 2;
161             annotations->max = size;
162             annotations->data = (anno_list_t *) realloc(annotations->data, sizeof(anno_list_t *) * size);
163          }
164
165          annotations->data[id] = (void *) a;
166
167          return true;
168       }
169
170       template<class T> 
171       bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const
172       {
173          if (!annotations)
174             return false;
175
176          int id = a_id.getID();
177
178          if (id > annotations->max) 
179          {
180             return false;
181          }
182
183          a = (T *) annotations->data[id];
184          if (!a) return false;
185
186          return true;
187       }
188
189       template<class T> 
190       bool removeAnnotation(AnnotationClass<T> &a_id)
191       {
192          if (!annotations) return false;
193
194          int id = a_id.getID();
195          if (id > annotations->max) 
196          {
197             return false;
198          }
199
200          if (!annotations->data[id]) 
201             return false;
202
203          annotations->data[id] = NULL;
204
205          return true;
206       }
207
208 };
209
210 class AnnotatableSparse
211 {
212    public:
213       struct void_ptr_hasher
214       {
215          size_t operator()(const void* a) const
216          {
217             return (size_t) a;
218          }
219       };
220
221 #if defined (_MSC_VER)
222       typedef dyn_hash_map<void *, void *> annos_by_type_t;
223 #else
224       typedef dyn_hash_map<void *, void *, void_ptr_hasher> annos_by_type_t;
225 #endif
226
227       typedef std::vector<annos_by_type_t *> annos_t;
228
229    private:
230
231       COMMON_EXPORT static annos_t annos;
232
233       template <class T>
234       annos_by_type_t *getAnnosOfType(AnnotationClass<T> &a_id, bool do_create =false) const
235       {
236          int aid = a_id.getID();
237
238          long nelems_to_create = aid - annos.size() + 1;
239
240          if (nelems_to_create > 0)
241          {
242             if (!do_create)
243             {
244                return NULL;
245             }
246
247             while (nelems_to_create)
248             {
249                annos_by_type_t *newl = new annos_by_type_t();
250                annos.push_back(newl);
251                nelems_to_create--;
252             }
253          }
254
255          annos_by_type_t *abt = annos[aid];
256
257          return abt;
258       }
259
260       void *getAnnosForObject(annos_by_type_t *abt,
261             void *obj, bool do_create = false) const 
262       {
263          assert(abt);
264          assert(obj);
265
266          void  *target = NULL;
267
268          annos_by_type_t::iterator iter = abt->find(obj);
269
270          if (iter == abt->end())
271          {
272             if (!do_create)
273             {
274                return NULL;
275             }
276
277             (*abt)[obj] = target;
278          }
279          else
280          {
281             target = iter->second;
282          }
283
284          return target;
285       }
286
287    public:
288       bool operator==(AnnotatableSparse &cmp)
289       {
290          unsigned this_ntypes = annos.size();
291          unsigned cmp_ntypes = cmp.annos.size();
292          unsigned ntypes = (cmp_ntypes > this_ntypes) ? cmp_ntypes : this_ntypes;
293
294          for (unsigned int i = 0; i < ntypes; ++i) 
295          {
296             if ((i >= cmp_ntypes) || (i >= this_ntypes)) 
297             {
298                //  compare is done since at least one set of annotations
299                //  has been exhausted
300                break;
301             }
302
303             annos_by_type_t *this_abt = annos[i];
304             annos_by_type_t *cmp_abt = cmp.annos[i];
305
306             if (!this_abt) 
307             {
308                fprintf(stderr, "%s[%d]:  WEIRD: FIXME\n", FILE__, __LINE__);
309                continue;
310             }
311
312             if (!cmp_abt) 
313             {
314                fprintf(stderr, "%s[%d]:  WEIRD: FIXME\n", FILE__, __LINE__);
315                continue;
316             }
317
318             annos_by_type_t::iterator this_abt_iter = this_abt->find(this);
319             annos_by_type_t::iterator cmp_abt_iter = cmp_abt->find(&cmp);
320
321             //  if one has annotations of this particular type and other other
322             //  doesn't, then we are def. not equal, so fail:
323
324             if (this_abt_iter == this_abt->end())
325             {
326                if (cmp_abt_iter != cmp_abt->end())
327                {
328                   return false;
329                }
330
331                //  both are at end()
332                continue;
333             }
334
335             if (   (cmp_abt_iter == cmp_abt->end())
336                   && (this_abt_iter != this_abt->end()))
337             {
338                return false;
339             }
340
341             AnnotationClassBase *acb = AnnotationClassBase::findAnnotationClass(i);
342
343             if (!acb)
344             {
345                fprintf(stderr, "%s[%d]:  cannot find annotation class for id %d\n", 
346                      FILE__, __LINE__, i);
347                return false;
348             }
349
350             //  both have annotation -- do the compare
351             anno_cmp_func_t cmpfunc = acb->getCmpFunc();
352
353             if (!cmpfunc)
354             {
355                //  even if not explicitly specified, a default pointer-compare
356                //  function should be returned here.
357
358                fprintf(stderr, "%s[%d]:  no cmp func for anno id %d\n", 
359                      FILE__, __LINE__, i);
360                return false;
361             }
362
363             void *arg1 = cmp_abt_iter->second;
364             void *arg2 = this_abt_iter->second;
365
366             bool ret = (*cmpfunc)(arg1, arg2);
367
368             return ret;
369          }
370
371          return true;
372       }
373
374       template<class T>
375       bool addAnnotation(T *a, AnnotationClass<T> &a_id)
376          {
377             void *obj = this;
378             annos_by_type_t *abt = getAnnosOfType(a_id, true /*do create if needed*/);
379             assert(abt);
380
381             annos_by_type_t::iterator iter = abt->find(obj);
382             if (iter == abt->end())
383             {
384                (*abt)[obj] = (void *)a;
385             }
386             else
387             {
388                //  if the annotation already exists and is identical (by pointer, of course)
389                //  what is the best solution?  Replacement makes no sense, since it is the
390                //  same.  The question is -- do we fail and report this situation as a logic
391                //  error?  This is probably the most conservative and hence safest approach,
392                //  but, since the pointer is identical, let's play nice and just report 
393                //  success?
394
395                return true;
396
397                //  maybe want to do (silent) replace here?
398                //fprintf(stderr, "%s[%d]:  failing to add already existing annotation here\n", FILE__, __LINE__);
399                //return false;
400
401             }
402
403             return true;
404          }
405
406       template<class T>
407       bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const 
408       {
409          a = NULL;
410
411          annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
412
413          if (!abt)
414          {
415             //fprintf(stderr, "%s[%d]:  no annotations of type %s\n",
416             //      FILE__, __LINE__, a_id.getName().c_str());
417             return false;
418          }
419
420          AnnotatableSparse * this_noconst = const_cast<AnnotatableSparse *>(this);
421          void *annos_for_object = getAnnosForObject(abt, (void *)this_noconst,
422                false /*no create if none*/);
423
424          if (!annos_for_object)
425          {
426             //fprintf(stderr, "%s[%d]:  no annotations of type %s\n", 
427             //      FILE__, __LINE__, a_id->getName().c_str());
428             return false;
429          }
430
431          a = (T *)annos_for_object;
432          return true;
433       }
434
435 #if 0
436       template<class T>
437          bool clearAnnotationsOfType(AnnotationClass<T> &a_id)
438          {
439             annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
440
441             if (!abt)
442             {
443                return false;
444             }
445
446             int nelem_cleared = abt->size();
447             abt->clear();
448
449             return (nelem_cleared != 0);
450          }
451 #endif
452
453       template<class T>
454       bool removeAnnotation(AnnotationClass<T> &a_id)
455       {
456          int aid = a_id.getID();
457
458          if (aid >= annos.size()) 
459          {
460             fprintf(stderr, "%s[%d]:  failed to remove nonexistant annotation\n", 
461                     __FILE__, __LINE__);
462             return false;
463          }
464
465          annos_t::iterator a_iter(aid);
466          annos.erase(a_iter);
467          //annos.erase(aid);
468
469 #if 0
470          int nelems_to_create = aid - annos.size() + 1;
471
472          if (nelems_to_create > 0)
473          {
474             if (!do_create)
475             {
476                return NULL;
477             }
478
479             while (nelems_to_create)
480             {
481                annos_by_type_t *newl = new annos_by_type_t();
482                annos.push_back(newl);
483                nelems_to_create--;
484             }
485          }
486
487          annos_by_type_t *abt = annos[aid];
488          annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
489
490          if (!abt)
491          {
492             return false;
493          }
494
495          annos_by_type_t::iterator iter = abt->find(obj);
496          if (iter == abt->end())
497          {
498             fprintf(stderr, "%s[%d]:  failing to remove already nonexistant annotation here\n", FILE__, __LINE__);
499             return false;
500          }
501          else
502          {
503             abt->erase(iter);
504          }
505
506 #endif
507          return true;
508       }
509
510 };
511
512 //COMMON_EXPORT AnnotatableSparse::annos_t annos;
513
514 //AnnotatableSparse::annos_t AnnotatableSparse::annos;
515 } // namespace
516
517 #endif