TypeLocBuilder.h revision 218887
11541Srgrimes//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
21541Srgrimes//
31541Srgrimes//                     The LLVM Compiler Infrastructure
41541Srgrimes//
51541Srgrimes// This file is distributed under the University of Illinois Open Source
61541Srgrimes// License. See LICENSE.TXT for details.
71541Srgrimes//
81541Srgrimes//===----------------------------------------------------------------------===//
91541Srgrimes//
101541Srgrimes//  This files defines TypeLocBuilder, a class for building TypeLocs
111541Srgrimes//  bottom-up.
121541Srgrimes//
131541Srgrimes//===----------------------------------------------------------------------===//
141541Srgrimes
151541Srgrimes#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
161541Srgrimes#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
171541Srgrimes
181541Srgrimes#include "clang/AST/TypeLoc.h"
191541Srgrimes#include "llvm/ADT/SmallVector.h"
201541Srgrimes#include "clang/AST/ASTContext.h"
211541Srgrimes
221541Srgrimesnamespace clang {
231541Srgrimes
241541Srgrimesclass TypeLocBuilder {
251541Srgrimes  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
261541Srgrimes
271541Srgrimes  /// The underlying location-data buffer.  Data grows from the end
281541Srgrimes  /// of the buffer backwards.
291541Srgrimes  char *Buffer;
301541Srgrimes
311541Srgrimes  /// The capacity of the current buffer.
321541Srgrimes  size_t Capacity;
331541Srgrimes
341541Srgrimes  /// The index of the first occupied byte in the buffer.
351541Srgrimes  size_t Index;
361541Srgrimes
371541Srgrimes#ifndef NDEBUG
381541Srgrimes  /// The last type pushed on this builder.
3950477Speter  QualType LastTy;
401541Srgrimes#endif
411541Srgrimes
4213203Swollman  /// The inline buffer.
43101127Srwatson  char InlineBuffer[InlineCapacity];
4413203Swollman
451541Srgrimes public:
462112Swollman  TypeLocBuilder()
4769664Speter    : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity)
4876166Smarkm  {}
49101127Srwatson
5089316Salfred  ~TypeLocBuilder() {
511541Srgrimes    if (Buffer != InlineBuffer)
521541Srgrimes      delete[] Buffer;
531541Srgrimes  }
541541Srgrimes
551541Srgrimes  /// Ensures that this buffer has at least as much capacity as described.
561541Srgrimes  void reserve(size_t Requested) {
571541Srgrimes    if (Requested > Capacity)
581541Srgrimes      // For now, match the request exactly.
591541Srgrimes      grow(Requested);
6092751Sjeff  }
6132011Sbde
621541Srgrimes  /// Pushes a copy of the given TypeLoc onto this builder.  The builder
6369664Speter  /// must be empty for this to work.
6469664Speter  void pushFullCopy(TypeLoc L) {
6592751Sjeff    size_t Size = L.getFullDataSize();
6669664Speter    TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
6769664Speter    memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
6869664Speter  }
6969664Speter
7092654Sjeff  /// Pushes uninitialized space for the given type.  The builder must
7192654Sjeff  /// be empty.
7269664Speter  TypeLoc pushFullUninitialized(QualType T) {
7369664Speter    return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
7469664Speter  }
7569664Speter
7669664Speter  /// Pushes space for a typespec TypeLoc.  Invalidates any TypeLocs
771541Srgrimes  /// previously retrieved from this builder.
781541Srgrimes  TypeSpecTypeLoc pushTypeSpec(QualType T) {
791541Srgrimes    size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
801541Srgrimes    return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
811541Srgrimes  }
821541Srgrimes
831541Srgrimes  /// Resets this builder to the newly-initialized state.
841541Srgrimes  void clear() {
851541Srgrimes#ifndef NDEBUG
861541Srgrimes    LastTy = QualType();
871541Srgrimes#endif
881541Srgrimes    Index = Capacity;
891541Srgrimes  }
901541Srgrimes
911541Srgrimes  /// Pushes space for a new TypeLoc of the given type.  Invalidates
921541Srgrimes  /// any TypeLocs previously retrieved from this builder.
931541Srgrimes  template <class TyLocType> TyLocType push(QualType T) {
941541Srgrimes    size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
951541Srgrimes    return cast<TyLocType>(pushImpl(T, LocalSize));
961541Srgrimes  }
971541Srgrimes
981541Srgrimes  /// Creates a TypeSourceInfo for the given type.
991541Srgrimes  TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
1001541Srgrimes#ifndef NDEBUG
1011541Srgrimes    assert(T == LastTy && "type doesn't match last type pushed!");
1021541Srgrimes#endif
1031541Srgrimes
1041541Srgrimes    size_t FullDataSize = Capacity - Index;
1051541Srgrimes    TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
1061541Srgrimes    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
10783366Sjulian    return DI;
10883366Sjulian  }
1091541Srgrimes
11091419Sjhbprivate:
11183366Sjulian  TypeLoc pushImpl(QualType T, size_t LocalSize) {
11242408Seivind#ifndef NDEBUG
11342453Seivind    QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
11442408Seivind    assert(TLast == LastTy &&
11542453Seivind           "mismatch between last type and new type's inner type");
11683366Sjulian    LastTy = T;
1171541Srgrimes#endif
1181541Srgrimes
1191541Srgrimes    // If we need to grow, grow by a factor of 2.
1201541Srgrimes    if (LocalSize > Index) {
1211541Srgrimes      size_t RequiredCapacity = Capacity + (LocalSize - Index);
1221541Srgrimes      size_t NewCapacity = Capacity * 2;
12392751Sjeff      while (RequiredCapacity > NewCapacity)
1241541Srgrimes        NewCapacity *= 2;
1251541Srgrimes      grow(NewCapacity);
12636735Sdfr    }
1271541Srgrimes
1281541Srgrimes    Index -= LocalSize;
12936735Sdfr
13020069Sbde    return getTypeLoc(T);
13120069Sbde  }
13220069Sbde
13320069Sbde  /// Grow to the given capacity.
13420069Sbde  void grow(size_t NewCapacity) {
13520069Sbde    assert(NewCapacity > Capacity);
13620069Sbde
1371541Srgrimes    // Allocate the new buffer and copy the old data into it.
13892751Sjeff    char *NewBuffer = new char[NewCapacity];
139100613Srwatson    unsigned NewIndex = Index + NewCapacity - Capacity;
140100613Srwatson    memcpy(&NewBuffer[NewIndex],
141100613Srwatson           &Buffer[Index],
142100613Srwatson           Capacity - Index);
1431541Srgrimes
1441541Srgrimes    if (Buffer != InlineBuffer)
1451541Srgrimes      delete[] Buffer;
1461541Srgrimes
1471541Srgrimes    Buffer = NewBuffer;
14897994Sjhb    Capacity = NewCapacity;
14997994Sjhb    Index = NewIndex;
15097994Sjhb  }
15197994Sjhb
15297994Sjhb  TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
1531541Srgrimes#ifndef NDEBUG
1541541Srgrimes    assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
1551541Srgrimes    LastTy = T;
1561541Srgrimes#endif
1571541Srgrimes    assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
15889306Salfred
15933360Sdyson    reserve(Size);
16051649Sphk    Index -= Size;
16133360Sdyson
1621541Srgrimes    return getTypeLoc(T);
1631541Srgrimes  }
16489306Salfred
1651541Srgrimes
1661541Srgrimes  // This is private because, when we kill off TypeSourceInfo in favor
1671541Srgrimes  // of TypeLoc, we'll want an interface that creates a TypeLoc given
1681541Srgrimes  // an ASTContext, and we don't want people to think they can just
1691541Srgrimes  // use this as an equivalent.
1701541Srgrimes  TypeLoc getTypeLoc(QualType T) {
1711541Srgrimes#ifndef NDEBUG
1721541Srgrimes    assert(LastTy == T && "type doesn't match last type pushed!");
1731541Srgrimes#endif
1741541Srgrimes    return TypeLoc(T, &Buffer[Index]);
1751541Srgrimes  }
1761541Srgrimes};
1771541Srgrimes
1781541Srgrimes}
1791541Srgrimes
1801541Srgrimes#endif
1813148Sphk