| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_CONTAINERS_STACK_CONTAINER_H_ | 
 | #define BASE_CONTAINERS_STACK_CONTAINER_H_ | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "base/macros.h" | 
 | #include "build/build_config.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | // This allocator can be used with STL containers to provide a stack buffer | 
 | // from which to allocate memory and overflows onto the heap. This stack buffer | 
 | // would be allocated on the stack and allows us to avoid heap operations in | 
 | // some situations. | 
 | // | 
 | // STL likes to make copies of allocators, so the allocator itself can't hold | 
 | // the data. Instead, we make the creator responsible for creating a | 
 | // StackAllocator::Source which contains the data. Copying the allocator | 
 | // merely copies the pointer to this shared source, so all allocators created | 
 | // based on our allocator will share the same stack buffer. | 
 | // | 
 | // This stack buffer implementation is very simple. The first allocation that | 
 | // fits in the stack buffer will use the stack buffer. Any subsequent | 
 | // allocations will not use the stack buffer, even if there is unused room. | 
 | // This makes it appropriate for array-like containers, but the caller should | 
 | // be sure to reserve() in the container up to the stack buffer size. Otherwise | 
 | // the container will allocate a small array which will "use up" the stack | 
 | // buffer. | 
 | template<typename T, size_t stack_capacity> | 
 | class StackAllocator : public std::allocator<T> { | 
 |  public: | 
 |   typedef typename std::allocator<T>::pointer pointer; | 
 |   typedef typename std::allocator<T>::size_type size_type; | 
 |  | 
 |   // Backing store for the allocator. The container owner is responsible for | 
 |   // maintaining this for as long as any containers using this allocator are | 
 |   // live. | 
 |   struct Source { | 
 |     Source() : used_stack_buffer_(false) { | 
 |     } | 
 |  | 
 |     // Casts the buffer in its right type. | 
 |     T* stack_buffer() { return reinterpret_cast<T*>(stack_buffer_); } | 
 |     const T* stack_buffer() const { | 
 |       return reinterpret_cast<const T*>(&stack_buffer_); | 
 |     } | 
 |  | 
 |     // The buffer itself. It is not of type T because we don't want the | 
 |     // constructors and destructors to be automatically called. Define a POD | 
 |     // buffer of the right size instead. | 
 |     alignas(T) char stack_buffer_[sizeof(T[stack_capacity])]; | 
 | #if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY) | 
 |     static_assert(alignof(T) <= 16, "http://crbug.com/115612"); | 
 | #endif | 
 |  | 
 |     // Set when the stack buffer is used for an allocation. We do not track | 
 |     // how much of the buffer is used, only that somebody is using it. | 
 |     bool used_stack_buffer_; | 
 |   }; | 
 |  | 
 |   // Used by containers when they want to refer to an allocator of type U. | 
 |   template<typename U> | 
 |   struct rebind { | 
 |     typedef StackAllocator<U, stack_capacity> other; | 
 |   }; | 
 |  | 
 |   // For the straight up copy c-tor, we can share storage. | 
 |   StackAllocator(const StackAllocator<T, stack_capacity>& rhs) | 
 |       : std::allocator<T>(), source_(rhs.source_) { | 
 |   } | 
 |  | 
 |   // ISO C++ requires the following constructor to be defined, | 
 |   // and std::vector in VC++2008SP1 Release fails with an error | 
 |   // in the class _Container_base_aux_alloc_real (from <xutility>) | 
 |   // if the constructor does not exist. | 
 |   // For this constructor, we cannot share storage; there's | 
 |   // no guarantee that the Source buffer of Ts is large enough | 
 |   // for Us. | 
 |   // TODO: If we were fancy pants, perhaps we could share storage | 
 |   // iff sizeof(T) == sizeof(U). | 
 |   template<typename U, size_t other_capacity> | 
 |   StackAllocator(const StackAllocator<U, other_capacity>& other) | 
 |       : source_(NULL) { | 
 |   } | 
 |  | 
 |   // This constructor must exist. It creates a default allocator that doesn't | 
 |   // actually have a stack buffer. glibc's std::string() will compare the | 
 |   // current allocator against the default-constructed allocator, so this | 
 |   // should be fast. | 
 |   StackAllocator() : source_(NULL) { | 
 |   } | 
 |  | 
 |   explicit StackAllocator(Source* source) : source_(source) { | 
 |   } | 
 |  | 
 |   // Actually do the allocation. Use the stack buffer if nobody has used it yet | 
 |   // and the size requested fits. Otherwise, fall through to the standard | 
 |   // allocator. | 
 |   pointer allocate(size_type n, void* hint = 0) { | 
 |     if (source_ != NULL && !source_->used_stack_buffer_ | 
 |         && n <= stack_capacity) { | 
 |       source_->used_stack_buffer_ = true; | 
 |       return source_->stack_buffer(); | 
 |     } else { | 
 |       return std::allocator<T>::allocate(n, hint); | 
 |     } | 
 |   } | 
 |  | 
 |   // Free: when trying to free the stack buffer, just mark it as free. For | 
 |   // non-stack-buffer pointers, just fall though to the standard allocator. | 
 |   void deallocate(pointer p, size_type n) { | 
 |     if (source_ != NULL && p == source_->stack_buffer()) | 
 |       source_->used_stack_buffer_ = false; | 
 |     else | 
 |       std::allocator<T>::deallocate(p, n); | 
 |   } | 
 |  | 
 |  private: | 
 |   Source* source_; | 
 | }; | 
 |  | 
 | // A wrapper around STL containers that maintains a stack-sized buffer that the | 
 | // initial capacity of the vector is based on. Growing the container beyond the | 
 | // stack capacity will transparently overflow onto the heap. The container must | 
 | // support reserve(). | 
 | // | 
 | // This will not work with std::string since some implementations allocate | 
 | // more bytes than requested in calls to reserve(), forcing the allocation onto | 
 | // the heap.  http://crbug.com/709273 | 
 | // | 
 | // WATCH OUT: the ContainerType MUST use the proper StackAllocator for this | 
 | // type. This object is really intended to be used only internally. You'll want | 
 | // to use the wrappers below for different types. | 
 | template<typename TContainerType, int stack_capacity> | 
 | class StackContainer { | 
 |  public: | 
 |   typedef TContainerType ContainerType; | 
 |   typedef typename ContainerType::value_type ContainedType; | 
 |   typedef StackAllocator<ContainedType, stack_capacity> Allocator; | 
 |  | 
 |   // Allocator must be constructed before the container! | 
 |   StackContainer() : allocator_(&stack_data_), container_(allocator_) { | 
 |     // Make the container use the stack allocation by reserving our buffer size | 
 |     // before doing anything else. | 
 |     container_.reserve(stack_capacity); | 
 |   } | 
 |  | 
 |   // Getters for the actual container. | 
 |   // | 
 |   // Danger: any copies of this made using the copy constructor must have | 
 |   // shorter lifetimes than the source. The copy will share the same allocator | 
 |   // and therefore the same stack buffer as the original. Use std::copy to | 
 |   // copy into a "real" container for longer-lived objects. | 
 |   ContainerType& container() { return container_; } | 
 |   const ContainerType& container() const { return container_; } | 
 |  | 
 |   // Support operator-> to get to the container. This allows nicer syntax like: | 
 |   //   StackContainer<...> foo; | 
 |   //   std::sort(foo->begin(), foo->end()); | 
 |   ContainerType* operator->() { return &container_; } | 
 |   const ContainerType* operator->() const { return &container_; } | 
 |  | 
 | #ifdef UNIT_TEST | 
 |   // Retrieves the stack source so that that unit tests can verify that the | 
 |   // buffer is being used properly. | 
 |   const typename Allocator::Source& stack_data() const { | 
 |     return stack_data_; | 
 |   } | 
 | #endif | 
 |  | 
 |  protected: | 
 |   typename Allocator::Source stack_data_; | 
 |   Allocator allocator_; | 
 |   ContainerType container_; | 
 |  | 
 |  private: | 
 |   DISALLOW_COPY_AND_ASSIGN(StackContainer); | 
 | }; | 
 |  | 
 | // StackVector ----------------------------------------------------------------- | 
 |  | 
 | // Example: | 
 | //   StackVector<int, 16> foo; | 
 | //   foo->push_back(22);  // we have overloaded operator-> | 
 | //   foo[0] = 10;         // as well as operator[] | 
 | template<typename T, size_t stack_capacity> | 
 | class StackVector : public StackContainer< | 
 |     std::vector<T, StackAllocator<T, stack_capacity> >, | 
 |     stack_capacity> { | 
 |  public: | 
 |   StackVector() : StackContainer< | 
 |       std::vector<T, StackAllocator<T, stack_capacity> >, | 
 |       stack_capacity>() { | 
 |   } | 
 |  | 
 |   // We need to put this in STL containers sometimes, which requires a copy | 
 |   // constructor. We can't call the regular copy constructor because that will | 
 |   // take the stack buffer from the original. Here, we create an empty object | 
 |   // and make a stack buffer of its own. | 
 |   StackVector(const StackVector<T, stack_capacity>& other) | 
 |       : StackContainer< | 
 |             std::vector<T, StackAllocator<T, stack_capacity> >, | 
 |             stack_capacity>() { | 
 |     this->container().assign(other->begin(), other->end()); | 
 |   } | 
 |  | 
 |   StackVector<T, stack_capacity>& operator=( | 
 |       const StackVector<T, stack_capacity>& other) { | 
 |     this->container().assign(other->begin(), other->end()); | 
 |     return *this; | 
 |   } | 
 |  | 
 |   // Vectors are commonly indexed, which isn't very convenient even with | 
 |   // operator-> (using "->at()" does exception stuff we don't want). | 
 |   T& operator[](size_t i) { return this->container().operator[](i); } | 
 |   const T& operator[](size_t i) const { | 
 |     return this->container().operator[](i); | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_CONTAINERS_STACK_CONTAINER_H_ |