15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef COURGETTE_MEMORY_ALLOCATOR_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define COURGETTE_MEMORY_ALLOCATOR_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <memory>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/file.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper class to track down call sites that are not handling error cases.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CheckReturnValue {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not marked explicit on purpose.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckReturnValue(T value) : value_(value), checked_(false) {  // NOLINT
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckReturnValue(const CheckReturnValue& other)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : value_(other.value_), checked_(other.checked_) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    other.checked_ = true;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckReturnValue& operator=(const CheckReturnValue& other) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (this != &other) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(checked_);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value_ = other.value_;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      checked_ = other.checked_;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      other.checked_ = true;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CheckReturnValue() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(checked_);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  operator const T&() const {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    checked_ = true;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value_;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T value_;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable bool checked_;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef CheckReturnValue<bool> CheckBool;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef bool CheckBool;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace courgette {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Manages a read/write virtual mapping of a physical file.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FileMapping {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileMapping();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~FileMapping();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Map a file from beginning to |size|.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Create(HANDLE file, size_t size);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Close();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true iff a mapping has been created.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool valid() const;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a writable pointer to the beginning of the memory mapped file.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If Create has not been called successfully, return value is NULL.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* view() const;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool InitializeView(size_t size);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE mapping_;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* view_;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Manages a temporary file and a memory mapping of the temporary file.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The memory that this class manages holds a pointer back to the TempMapping
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object itself, so that given a memory pointer allocated by this class,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// you can get a pointer to the TempMapping instance that owns that memory.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TempMapping {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TempMapping();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~TempMapping();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a temporary file of size |size| and maps it into the current
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // process's address space.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Initialize(size_t size);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a writable pointer to the reserved memory.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* memory() const;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if the mapping is valid and memory is available.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool valid() const;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a pointer to the TempMapping instance that allocated the |mem|
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // block of memory.  It's the callers responsibility to make sure that
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the memory block was allocated by the TempMapping class.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TempMapping* GetMappingFromPtr(void* mem);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File file_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileMapping mapping_;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A memory allocator class that allocates memory either from the heap or via a
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// temporary file.  The interface is STL inspired but the class does not throw
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// STL exceptions on allocation failure.  Instead it returns NULL.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A file allocation will be made if either the requested memory size exceeds
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |kMaxHeapAllocationSize| or if a heap allocation fails.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Allocating the memory as a mapping of a temporary file solves the problem
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that there might not be enough physical memory and pagefile to support the
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocation.  This can happen because these resources are too small, or
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// already committed to other processes.  Provided there is enough disk, the
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// temporary file acts like a pagefile that other processes can't access.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T>
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryAllocator {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef T value_type;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef value_type* pointer;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef value_type& reference;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef const value_type* const_pointer;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef const value_type& const_reference;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef size_t size_type;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef ptrdiff_t difference_type;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Each allocation is tagged with a single byte so that we know how to
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deallocate it.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum AllocationType {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HEAP_ALLOCATION,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_ALLOCATION,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 5MB is the maximum heap allocation size that we'll attempt.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When applying a patch for Chrome 10.X we found that at this
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // threshold there were 17 allocations higher than this threshold
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (largest at 136MB) 10 allocations just below the threshold and 6362
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // smaller allocations.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kMaxHeapAllocationSize = 1024 * 1024 * 5;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<class OtherT>
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct rebind {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // convert a MemoryAllocator<T> to a MemoryAllocator<OtherT>
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typedef MemoryAllocator<OtherT> other;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryAllocator() _THROW0() {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can't use an explicit constructor here, as dictated by our style guide.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The implementation of basic_string in Visual Studio 2010 prevents this.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryAllocator(const MemoryAllocator<T>& other) _THROW0() {  // NOLINT
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<class OtherT>
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryAllocator(const MemoryAllocator<OtherT>& other) _THROW0() {  // NOLINT
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~MemoryAllocator() {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void deallocate(pointer ptr, size_type size) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8* mem = reinterpret_cast<uint8*>(ptr);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mem -= sizeof(T);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mem[0] == HEAP_ALLOCATION) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete [] mem;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(static_cast<uint8>(FILE_ALLOCATION), mem[0]);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TempMapping* mapping = TempMapping::GetMappingFromPtr(mem);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete mapping;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pointer allocate(size_type count) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We use the first byte of each allocation to mark the allocation type.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // However, so that the allocation is properly aligned, we allocate an
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // extra element and then use the first byte of the first element
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to mark the allocation type.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count++;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count > max_size())
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_type bytes = count * sizeof(T);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8* mem = NULL;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First see if we can do this allocation on the heap.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count < kMaxHeapAllocationSize)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem = new(std::nothrow) uint8[bytes];
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mem != NULL) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem[0] = static_cast<uint8>(HEAP_ALLOCATION);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If either the heap allocation failed or the request exceeds the
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // max heap allocation threshold, we back the allocation with a temp file.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TempMapping* mapping = new(std::nothrow) TempMapping();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (mapping && mapping->Initialize(bytes)) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mem = reinterpret_cast<uint8*>(mapping->memory());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mem[0] = static_cast<uint8>(FILE_ALLOCATION);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return mem ? reinterpret_cast<pointer>(mem + sizeof(T)) : NULL;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pointer allocate(size_type count, const void* hint) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return allocate(count);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void construct(pointer ptr, const T& value) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::new(ptr) T(value);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void destroy(pointer ptr) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr->~T();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_type max_size() const _THROW0() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_type count = static_cast<size_type>(-1) / sizeof(T);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (0 < count ? count : 1);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else  // OS_WIN
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Mac, Linux, we use a bare bones implementation that only does
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// heap allocations.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<class T>
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryAllocator {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef T value_type;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef value_type* pointer;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef value_type& reference;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef const value_type* const_pointer;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef const value_type& const_reference;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef size_t size_type;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef ptrdiff_t difference_type;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<class OtherT>
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct rebind {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // convert a MemoryAllocator<T> to a MemoryAllocator<OtherT>
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typedef MemoryAllocator<OtherT> other;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryAllocator() {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MemoryAllocator(const MemoryAllocator<T>& other) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<class OtherT>
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MemoryAllocator(const MemoryAllocator<OtherT>& other) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~MemoryAllocator() {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void deallocate(pointer ptr, size_type size) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete [] ptr;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pointer allocate(size_type count) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count > max_size())
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return reinterpret_cast<pointer>(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new(std::nothrow) uint8[count * sizeof(T)]);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pointer allocate(size_type count, const void* hint) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return allocate(count);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void construct(pointer ptr, const T& value) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::new(ptr) T(value);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void destroy(pointer ptr) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr->~T();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_type max_size() const {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_type count = static_cast<size_type>(-1) / sizeof(T);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (0 < count ? count : 1);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_WIN
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Manages a growable buffer.  The buffer allocation is done by the
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MemoryAllocator class.  This class will not throw exceptions so call sites
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// must be prepared to handle memory allocation failures.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The interface is STL inspired to avoid having to make too many changes
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to code that previously was using STL.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename T, class Allocator = MemoryAllocator<T> >
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NoThrowBuffer {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef T value_type;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kAllocationFailure = 0xffffffff;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kStartSize = sizeof(T) > 0x100 ? 1 : 0x100 / sizeof(T);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NoThrowBuffer() : buffer_(NULL), size_(0), alloc_size_(0) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~NoThrowBuffer() {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clear();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void clear() {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer_) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alloc_.deallocate(buffer_, alloc_size_);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffer_ = NULL;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_ = 0;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alloc_size_ = 0;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool empty() const {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return size_ == 0;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckBool reserve(size_t size) WARN_UNUSED_RESULT {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (failed())
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size <= alloc_size_)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size < kStartSize)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size = kStartSize;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Use a size 1% higher than requested. In practice, this makes Courgette as
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // much as 5x faster on typical Chrome update payloads as a lot of future
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // reserve() calls will become no-ops instead of costly resizes that copy
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // all the data. Note that doing this here instead of outside the function
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // is more efficient, since it's after the no-op early return checks above.
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size *= 1.01;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    T* new_buffer = alloc_.allocate(size);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_buffer) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      clear();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alloc_size_ = kAllocationFailure;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (buffer_) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(new_buffer, buffer_, size_ * sizeof(T));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        alloc_.deallocate(buffer_, alloc_size_);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffer_ = new_buffer;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alloc_size_ = size;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !failed();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckBool append(const T* data, size_t size) WARN_UNUSED_RESULT {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (failed())
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > alloc_.max_size() - size_)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!size)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((alloc_size_ - size_) < size) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const size_t max_size = alloc_.max_size();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t new_size = alloc_size_ ? alloc_size_ : kStartSize;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (new_size < size_ + size) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (new_size < max_size - new_size) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new_size *= 2;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new_size = max_size;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!reserve(new_size))
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(buffer_ + size_, data, size * sizeof(T));
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_ += size;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckBool resize(size_t size, const T& init_value) WARN_UNUSED_RESULT {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > size_) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!reserve(size))
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = size_; i < size; ++i)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buffer_[i] = init_value;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (size < size_) {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(tommi): Should we allocate a new, smaller buffer?
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // It might be faster for us to simply change the size.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_ = size;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckBool push_back(const T& item) WARN_UNUSED_RESULT {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return append(&item, 1);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const T& back() const {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer_[size_ - 1];
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T& back() {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer_[size_ - 1];
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const T* begin() const {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!size_)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &buffer_[0];
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* begin() {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!size_)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &buffer_[0];
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const T* end() const {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!size_)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &buffer_[size_ - 1];
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* end() {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!size_)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &buffer_[size_ - 1];
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const T& operator[](size_t index) const {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(index < size_);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer_[index];
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T& operator[](size_t index) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(index < size_);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer_[index];
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size() const {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return size_;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* data() const {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer_;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if an allocation failure has ever occurred for this object.
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool failed() const {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return alloc_size_ == kAllocationFailure;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  T* buffer_;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size_;  // how much of the buffer we're using.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t alloc_size_;  // how much space we have allocated.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Allocator alloc_;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace courgette
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // COURGETTE_MEMORY_ALLOCATOR_H_
473