TypeLocBuilder.h revision 218893
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 110private: 111 TypeLoc pushImpl(QualType T, size_t LocalSize) { 112#ifndef NDEBUG 113 QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); 114 assert(TLast == LastTy && 115 "mismatch between last type and new type's inner type"); 116 LastTy = T; 117#endif 118 119 // If we need to grow, grow by a factor of 2. 120 if (LocalSize > Index) { 121 size_t RequiredCapacity = Capacity + (LocalSize - Index); 122 size_t NewCapacity = Capacity * 2; 123 while (RequiredCapacity > NewCapacity) 124 NewCapacity *= 2; 125 grow(NewCapacity); 126 } 127 128 Index -= LocalSize; 129 130 return getTypeLoc(T); 131 } 132 133 /// Grow to the given capacity. 134 void grow(size_t NewCapacity) { 135 assert(NewCapacity > Capacity); 136 137 // Allocate the new buffer and copy the old data into it. 138 char *NewBuffer = new char[NewCapacity]; 139 unsigned NewIndex = Index + NewCapacity - Capacity; 140 memcpy(&NewBuffer[NewIndex], 141 &Buffer[Index], 142 Capacity - Index); 143 144 if (Buffer != InlineBuffer) 145 delete[] Buffer; 146 147 Buffer = NewBuffer; 148 Capacity = NewCapacity; 149 Index = NewIndex; 150 } 151 152 TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) { 153#ifndef NDEBUG 154 assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder"); 155 LastTy = T; 156#endif 157 assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder"); 158 159 reserve(Size); 160 Index -= Size; 161 162 return getTypeLoc(T); 163 } 164 165 166 // This is private because, when we kill off TypeSourceInfo in favor 167 // of TypeLoc, we'll want an interface that creates a TypeLoc given 168 // an ASTContext, and we don't want people to think they can just 169 // use this as an equivalent. 170 TypeLoc getTypeLoc(QualType T) { 171#ifndef NDEBUG 172 assert(LastTy == T && "type doesn't match last type pushed!"); 173#endif 174 return TypeLoc(T, &Buffer[Index]); 175 } 176}; 177 178} 179 180#endif 181