TypeLocBuilder.h revision 219077
1//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This files defines TypeLocBuilder, a class for building TypeLocs
11//  bottom-up.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
16#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
17
18#include "clang/AST/TypeLoc.h"
19#include "llvm/ADT/SmallVector.h"
20#include "clang/AST/ASTContext.h"
21
22namespace clang {
23
24class TypeLocBuilder {
25  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
26
27  /// The underlying location-data buffer.  Data grows from the end
28  /// of the buffer backwards.
29  char *Buffer;
30
31  /// The capacity of the current buffer.
32  size_t Capacity;
33
34  /// The index of the first occupied byte in the buffer.
35  size_t Index;
36
37#ifndef NDEBUG
38  /// The last type pushed on this builder.
39  QualType LastTy;
40#endif
41
42  /// The inline buffer.
43  char InlineBuffer[InlineCapacity];
44
45 public:
46  TypeLocBuilder()
47    : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity)
48  {}
49
50  ~TypeLocBuilder() {
51    if (Buffer != InlineBuffer)
52      delete[] Buffer;
53  }
54
55  /// Ensures that this buffer has at least as much capacity as described.
56  void reserve(size_t Requested) {
57    if (Requested > Capacity)
58      // For now, match the request exactly.
59      grow(Requested);
60  }
61
62  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
63  /// must be empty for this to work.
64  void pushFullCopy(TypeLoc L) {
65    size_t Size = L.getFullDataSize();
66    TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
67    memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
68  }
69
70  /// Pushes uninitialized space for the given type.  The builder must
71  /// be empty.
72  TypeLoc pushFullUninitialized(QualType T) {
73    return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
74  }
75
76  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
77  /// previously retrieved from this builder.
78  TypeSpecTypeLoc pushTypeSpec(QualType T) {
79    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
80    return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
81  }
82
83  /// Resets this builder to the newly-initialized state.
84  void clear() {
85#ifndef NDEBUG
86    LastTy = QualType();
87#endif
88    Index = Capacity;
89  }
90
91  /// Pushes space for a new TypeLoc of the given type.  Invalidates
92  /// any TypeLocs previously retrieved from this builder.
93  template <class TyLocType> TyLocType push(QualType T) {
94    size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
95    return cast<TyLocType>(pushImpl(T, LocalSize));
96  }
97
98  /// Creates a TypeSourceInfo for the given type.
99  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
100#ifndef NDEBUG
101    assert(T == LastTy && "type doesn't match last type pushed!");
102#endif
103
104    size_t FullDataSize = Capacity - Index;
105    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
106    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
107    return DI;
108  }
109
110  /// \brief Copies the type-location information to the given AST context and
111  /// returns a \c TypeLoc referring into the AST context.
112  TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
113#ifndef NDEBUG
114    assert(T == LastTy && "type doesn't match last type pushed!");
115#endif
116
117    size_t FullDataSize = Capacity - Index;
118    void *Mem = Context.Allocate(FullDataSize);
119    memcpy(Mem, &Buffer[Index], FullDataSize);
120    return TypeLoc(T, Mem);
121  }
122
123private:
124  TypeLoc pushImpl(QualType T, size_t LocalSize) {
125#ifndef NDEBUG
126    QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
127    assert(TLast == LastTy &&
128           "mismatch between last type and new type's inner type");
129    LastTy = T;
130#endif
131
132    // If we need to grow, grow by a factor of 2.
133    if (LocalSize > Index) {
134      size_t RequiredCapacity = Capacity + (LocalSize - Index);
135      size_t NewCapacity = Capacity * 2;
136      while (RequiredCapacity > NewCapacity)
137        NewCapacity *= 2;
138      grow(NewCapacity);
139    }
140
141    Index -= LocalSize;
142
143    return getTypeLoc(T);
144  }
145
146  /// Grow to the given capacity.
147  void grow(size_t NewCapacity) {
148    assert(NewCapacity > Capacity);
149
150    // Allocate the new buffer and copy the old data into it.
151    char *NewBuffer = new char[NewCapacity];
152    unsigned NewIndex = Index + NewCapacity - Capacity;
153    memcpy(&NewBuffer[NewIndex],
154           &Buffer[Index],
155           Capacity - Index);
156
157    if (Buffer != InlineBuffer)
158      delete[] Buffer;
159
160    Buffer = NewBuffer;
161    Capacity = NewCapacity;
162    Index = NewIndex;
163  }
164
165  TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
166#ifndef NDEBUG
167    assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
168    LastTy = T;
169#endif
170    assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
171
172    reserve(Size);
173    Index -= Size;
174
175    return getTypeLoc(T);
176  }
177
178
179  // This is private because, when we kill off TypeSourceInfo in favor
180  // of TypeLoc, we'll want an interface that creates a TypeLoc given
181  // an ASTContext, and we don't want people to think they can just
182  // use this as an equivalent.
183  TypeLoc getTypeLoc(QualType T) {
184#ifndef NDEBUG
185    assert(LastTy == T && "type doesn't match last type pushed!");
186#endif
187    return TypeLoc(T, &Buffer[Index]);
188  }
189};
190
191}
192
193#endif
194