summaryrefslogtreecommitdiff
path: root/include/llvm/Support/Annotation.h
blob: 2be1c1061690b2f08baa885d9e35546751168688 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//===-- llvm/Support/Annotation.h - Annotation classes ----------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declarations for two classes: Annotation & Annotable.
// Using these two simple classes, anything that derives from Annotable can have
// Annotation subclasses attached to them, ready for easy retrieval.
//
// Annotations are designed to be easily attachable to various classes.
//
// The AnnotationManager class is essential for using these classes.  It is
// responsible for turning Annotation name strings into tokens [unique id #'s]
// that may be used to search for and create annotations.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_ANNOTATION_H
#define LLVM_SUPPORT_ANNOTATION_H

#include <string>
#include <cassert>

namespace llvm {

class AnnotationID;
class Annotation;
class Annotable;
struct AnnotationManager;

//===----------------------------------------------------------------------===//
//
// AnnotationID - This class is a thin wrapper around an unsigned integer that
// is used to hopefully prevent errors using AnnotationID's.  They may be copied
// freely around and passed byvalue with little or no overhead.
//
class AnnotationID {
  friend struct AnnotationManager;
  unsigned ID;

  AnnotationID();                             // Default ctor is disabled

  // AnnotationID is only creatable from AnnMgr.
  explicit inline AnnotationID(unsigned i) : ID(i) {}
public:
  inline AnnotationID(const AnnotationID &A) : ID(A.ID) {}

  inline bool operator==(const AnnotationID &A) const {
    return A.ID == ID;
  }
  inline bool operator<(const AnnotationID &A) const {
    return ID < A.ID;
  }
};


//===----------------------------------------------------------------------===//
//
// Annotation Class - This class serves as a base class for any specific
// annotations that you might need.  Simply subclass this to add extra
// information to the annotations.
//
class Annotation {
  friend class Annotable;  // Annotable manipulates Next list
  AnnotationID ID;         // ID number, as obtained from AnnotationManager
  Annotation *Next;        // The next annotation in the linked list
public:
  explicit inline Annotation(AnnotationID id) : ID(id), Next(0) {}
  virtual ~Annotation();  // Designed to be subclassed

  // getID - Return the unique ID# of this annotation
  inline AnnotationID getID() const { return ID; }

  // getNext - Return the next annotation in the list...
  inline Annotation *getNext() const { return Next; }
};


//===----------------------------------------------------------------------===//
//
// Annotable - This class is used as a base class for all objects that would
// like to have annotation capability.
//
// Annotable objects keep their annotation list sorted as annotations are
// inserted and deleted.  This is used to ensure that annotations with identical
// ID#'s are stored sequentially.
//
class Annotable {
  mutable Annotation *AnnotationList;

  Annotable(const Annotable &);        // Do not implement
  void operator=(const Annotable &);   // Do not implement
public:
  Annotable() : AnnotationList(0) {}
  ~Annotable();

  // getAnnotation - Search the list for annotations of the specified ID.  The
  // pointer returned is either null (if no annotations of the specified ID
  // exist), or it points to the first element of a potentially list of elements
  // with identical ID #'s.
  //
  Annotation *getAnnotation(AnnotationID ID) const {
    for (Annotation *A = AnnotationList; A; A = A->getNext())
      if (A->getID() == ID) return A;
    return 0;
  }

  // getOrCreateAnnotation - Search through the annotation list, if there is
  // no annotation with the specified ID, then use the AnnotationManager to
  // create one.
  //
  inline Annotation *getOrCreateAnnotation(AnnotationID ID) const;

  // addAnnotation - Insert the annotation into the list in a sorted location.
  //
  void addAnnotation(Annotation *A) const {
    assert(A->Next == 0 && "Annotation already in list?!?");

    Annotation **AL = &AnnotationList;
    while (*AL && (*AL)->ID < A->getID())  // Find where to insert annotation
      AL = &((*AL)->Next);
    A->Next = *AL;                         // Link the annotation in
    *AL = A;
  }

  // unlinkAnnotation - Remove the first annotation of the specified ID... and
  // then return the unlinked annotation.  The annotation object is not deleted.
  //
  inline Annotation *unlinkAnnotation(AnnotationID ID) const {
    for (Annotation **A = &AnnotationList; *A; A = &((*A)->Next))
      if ((*A)->getID() == ID) {
        Annotation *Ret = *A;
        *A = Ret->Next;
        Ret->Next = 0;
        return Ret;
      }
    return 0;
  }

  // deleteAnnotation - Delete the first annotation of the specified ID in the
  // list.  Unlink unlinkAnnotation, this actually deletes the annotation object
  //
  bool deleteAnnotation(AnnotationID ID) const {
    Annotation *A = unlinkAnnotation(ID);
    delete A;
    return A != 0;
  }
};


//===----------------------------------------------------------------------===//
//
// AnnotationManager - This class is primarily responsible for maintaining a
// one-to-one mapping between string Annotation names and Annotation ID numbers.
//
// Compared to the rest of the Annotation system, these mapping methods are
// relatively slow, so they should be avoided by locally caching Annotation
// ID #'s.  These methods are safe to call at any time, even by static ctors, so
// they should be used by static ctors most of the time.
//
// This class also provides support for annotations that are created on demand
// by the Annotable::getOrCreateAnnotation method.  To get this to work, simply
// register an annotation handler
//
struct AnnotationManager {
  typedef Annotation *(*Factory)(AnnotationID, const Annotable *, void*);

  //===--------------------------------------------------------------------===//
  // Basic ID <-> Name map functionality

  static AnnotationID         getID(const std::string &Name);  // Name -> ID
  static const std::string &getName(AnnotationID ID);          // ID -> Name

  // getID - Name -> ID + registration of a factory function for demand driven
  // annotation support.
  static AnnotationID getID(const std::string &Name, Factory Fact,
                            void *Data = 0);

  //===--------------------------------------------------------------------===//
  // Annotation creation on demand support...

  // registerAnnotationFactory - This method is used to register a callback
  // function used to create an annotation on demand if it is needed by the
  // Annotable::getOrCreateAnnotation method.
  //
  static void registerAnnotationFactory(AnnotationID ID, Factory Func,
                                        void *ExtraData = 0);

  // createAnnotation - Create an annotation of the specified ID for the
  // specified object, using a register annotation creation function.
  //
  static Annotation *createAnnotation(AnnotationID ID, const Annotable *Obj);
};



// getOrCreateAnnotation - Search through the annotation list, if there is
// no annotation with the specified ID, then use the AnnotationManager to
// create one.
//
inline Annotation *Annotable::getOrCreateAnnotation(AnnotationID ID) const {
  Annotation *A = getAnnotation(ID);   // Fast path, check for preexisting ann
  if (A) return A;

  // No annotation found, ask the annotation manager to create an annotation...
  A = AnnotationManager::createAnnotation(ID, this);
  assert(A && "AnnotationManager could not create annotation!");
  addAnnotation(A);
  return A;
}

} // End namespace llvm

#endif