#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
namespace clang {
class TypeLocBuilder {
enum { InlineCapacity = 8 * sizeof(SourceLocation) };
char *Buffer;
size_t Capacity;
size_t Index;
#ifndef NDEBUG
QualType LastTy;
#endif
char InlineBuffer[InlineCapacity];
public:
TypeLocBuilder()
: Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
~TypeLocBuilder() {
if (Buffer != InlineBuffer)
delete[] Buffer;
}
void reserve(size_t Requested) {
if (Requested > Capacity)
grow(Requested);
}
void pushFullCopy(TypeLoc L) {
size_t Size = L.getFullDataSize();
TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
}
TypeLoc pushFullUninitialized(QualType T) {
return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
}
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
}
void clear() {
#ifndef NDEBUG
LastTy = QualType();
#endif
Index = Capacity;
}
void TypeWasModifiedSafely(QualType T) {
#ifndef NDEBUG
LastTy = T;
#endif
}
template <class TyLocType> TyLocType push(QualType T) {
size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
return cast<TyLocType>(pushImpl(T, LocalSize));
}
TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
#ifndef NDEBUG
assert(T == LastTy && "type doesn't match last type pushed!");
#endif
size_t FullDataSize = Capacity - Index;
TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
return DI;
}
TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
#ifndef NDEBUG
assert(T == LastTy && "type doesn't match last type pushed!");
#endif
size_t FullDataSize = Capacity - Index;
void *Mem = Context.Allocate(FullDataSize);
memcpy(Mem, &Buffer[Index], FullDataSize);
return TypeLoc(T, Mem);
}
private:
TypeLoc pushImpl(QualType T, size_t LocalSize) {
#ifndef NDEBUG
QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
assert(TLast == LastTy &&
"mismatch between last type and new type's inner type");
LastTy = T;
#endif
if (LocalSize > Index) {
size_t RequiredCapacity = Capacity + (LocalSize - Index);
size_t NewCapacity = Capacity * 2;
while (RequiredCapacity > NewCapacity)
NewCapacity *= 2;
grow(NewCapacity);
}
Index -= LocalSize;
return getTemporaryTypeLoc(T);
}
void grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
char *NewBuffer = new char[NewCapacity];
unsigned NewIndex = Index + NewCapacity - Capacity;
memcpy(&NewBuffer[NewIndex],
&Buffer[Index],
Capacity - Index);
if (Buffer != InlineBuffer)
delete[] Buffer;
Buffer = NewBuffer;
Capacity = NewCapacity;
Index = NewIndex;
}
TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
#ifndef NDEBUG
assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
LastTy = T;
#endif
assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
reserve(Size);
Index -= Size;
return getTemporaryTypeLoc(T);
}
public:
TypeLoc getTemporaryTypeLoc(QualType T) {
#ifndef NDEBUG
assert(LastTy == T && "type doesn't match last type pushed!");
#endif
return TypeLoc(T, &Buffer[Index]);
}
};
}
#endif