Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef COURGETTE_MEMORY_ALLOCATOR_H_ | 5 #ifndef COURGETTE_MEMORY_ALLOCATOR_H_ |
| 6 #define COURGETTE_MEMORY_ALLOCATOR_H_ | 6 #define COURGETTE_MEMORY_ALLOCATOR_H_ |
| 7 | 7 |
| 8 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 49 mutable bool checked_; | 49 mutable bool checked_; |
| 50 }; | 50 }; |
| 51 typedef CheckReturnValue<bool> CheckBool; | 51 typedef CheckReturnValue<bool> CheckBool; |
| 52 #else | 52 #else |
| 53 typedef bool CheckBool; | 53 typedef bool CheckBool; |
| 54 #endif | 54 #endif |
| 55 | 55 |
| 56 namespace courgette { | 56 namespace courgette { |
| 57 | 57 |
| 58 #ifdef OS_WIN | 58 #ifdef OS_WIN |
| 59 // Prototype for the allocation handler function. | |
| 60 // See ThrowExceptionOnAllocationFailure below. | |
| 61 typedef void (__stdcall* AllocationFailureHandler)(uint32 err); | |
| 62 | |
| 63 // A helper function to help diagnose failures we've seen in the field. | |
| 64 // The function constructs a string containing the error and throws a runtime | |
| 65 // exception. The calling convention is set to stdcall to force argument | |
| 66 // passing via the stack. | |
| 67 __declspec(noinline) | |
| 68 void __stdcall ThrowExceptionOnAllocationFailure(uint32 err); | |
| 59 | 69 |
| 60 // Manages a temporary file. The file is created in the %TEMP% folder and | 70 // Manages a temporary file. The file is created in the %TEMP% folder and |
| 61 // is deleted when the file handle is closed. | 71 // is deleted when the file handle is closed. |
| 62 // NOTE: Since the file will be used as backing for a memory allocation, | 72 // NOTE: Since the file will be used as backing for a memory allocation, |
| 63 // it will never be so big that size_t cannot represent its size. | 73 // it will never be so big that size_t cannot represent its size. |
| 64 class TempFile { | 74 class TempFile { |
| 65 public: | 75 public: |
| 66 TempFile(); | 76 TempFile(); |
| 67 ~TempFile(); | 77 ~TempFile(); |
| 68 | 78 |
| 69 __declspec(noinline) void Create(); | 79 __declspec(noinline) bool Create(AllocationFailureHandler failure_handler); |
| 70 void Close(); | 80 void Close(); |
| 71 __declspec(noinline) void SetSize(size_t size); | 81 __declspec(noinline) bool SetSize(size_t size, |
| 82 AllocationFailureHandler failure_handler); | |
| 72 | 83 |
| 73 // Returns true iff the temp file is currently open. | 84 // Returns true iff the temp file is currently open. |
| 74 bool valid() const; | 85 bool valid() const; |
| 75 | 86 |
| 76 // Returns the handle of the temporary file or INVALID_HANDLE_VALUE if | 87 // Returns the handle of the temporary file or INVALID_HANDLE_VALUE if |
| 77 // a temp file has not been created. | 88 // a temp file has not been created. |
| 78 base::PlatformFile handle() const; | 89 base::PlatformFile handle() const; |
| 79 | 90 |
| 80 // Returns the size of the temp file. If the temp file doesn't exist, | 91 // Returns the size of the temp file. If the temp file doesn't exist, |
| 81 // the return value is 0. | 92 // the return value is 0. |
| 82 size_t size() const; | 93 size_t size() const; |
| 83 | 94 |
| 84 protected: | 95 protected: |
| 85 __declspec(noinline) FilePath PrepareTempFile(); | 96 __declspec(noinline) |
| 97 bool PrepareTempFile(FilePath* path, | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
move |path| after |failure_handler|: out params co
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 98 AllocationFailureHandler failure_handler); | |
| 86 | 99 |
| 87 base::PlatformFile file_; | 100 base::PlatformFile file_; |
| 88 size_t size_; | 101 size_t size_; |
| 89 }; | 102 }; |
| 90 | 103 |
| 91 // Manages a read/write virtual mapping of a physical file. | 104 // Manages a read/write virtual mapping of a physical file. |
| 92 class FileMapping { | 105 class FileMapping { |
| 93 public: | 106 public: |
| 94 FileMapping(); | 107 FileMapping(); |
| 95 ~FileMapping(); | 108 ~FileMapping(); |
| 96 | 109 |
| 97 // Map a file from beginning to |size|. | 110 // Map a file from beginning to |size|. |
| 98 __declspec(noinline) void Create(HANDLE file, size_t size); | 111 __declspec(noinline) bool Create(HANDLE file, size_t size, |
| 112 AllocationFailureHandler failure_handler); | |
| 99 void Close(); | 113 void Close(); |
| 100 | 114 |
| 101 // Returns true iff a mapping has been created. | 115 // Returns true iff a mapping has been created. |
| 102 bool valid() const; | 116 bool valid() const; |
| 103 | 117 |
| 104 // Returns a writable pointer to the beginning of the memory mapped file. | 118 // Returns a writable pointer to the beginning of the memory mapped file. |
| 105 // If Create has not been called successfully, return value is NULL. | 119 // If Create has not been called successfully, return value is NULL. |
| 106 void* view() const; | 120 void* view() const; |
| 107 | 121 |
| 108 protected: | 122 protected: |
| 109 __declspec(noinline) void InitializeView(size_t size); | 123 __declspec(noinline) |
| 124 bool InitializeView(size_t size, AllocationFailureHandler failure_handler); | |
| 110 | 125 |
| 111 HANDLE mapping_; | 126 HANDLE mapping_; |
| 112 void* view_; | 127 void* view_; |
| 113 }; | 128 }; |
| 114 | 129 |
| 115 // Manages a temporary file and a memory mapping of the temporary file. | 130 // Manages a temporary file and a memory mapping of the temporary file. |
| 116 // The memory that this class manages holds a pointer back to the TempMapping | 131 // The memory that this class manages holds a pointer back to the TempMapping |
| 117 // object itself, so that given a memory pointer allocated by this class, | 132 // object itself, so that given a memory pointer allocated by this class, |
| 118 // you can get a pointer to the TempMapping instance that owns that memory. | 133 // you can get a pointer to the TempMapping instance that owns that memory. |
| 119 class TempMapping { | 134 class TempMapping { |
| 120 public: | 135 public: |
| 121 TempMapping(); | 136 TempMapping(); |
| 122 ~TempMapping(); | 137 ~TempMapping(); |
| 123 | 138 |
| 124 // Creates a temporary file of size |size| and maps it into the current | 139 // Creates a temporary file of size |size| and maps it into the current |
| 125 // process' address space. | 140 // process' address space. |
| 126 __declspec(noinline) void Initialize(size_t size); | 141 __declspec(noinline) bool Initialize(size_t size, |
| 142 AllocationFailureHandler failure_handler); | |
| 127 | 143 |
| 128 // Returns a writable pointer to the reserved memory. | 144 // Returns a writable pointer to the reserved memory. |
| 129 void* memory() const; | 145 void* memory() const; |
| 130 | 146 |
| 147 // Returns true if the mapping is valid and memory is available. | |
| 148 bool valid() const; | |
| 149 | |
| 131 // Returns a pointer to the TempMapping instance that allocated the |mem| | 150 // Returns a pointer to the TempMapping instance that allocated the |mem| |
| 132 // block of memory. It's the callers responsibility to make sure that | 151 // block of memory. It's the callers responsibility to make sure that |
| 133 // the memory block was allocated by the TempMapping class. | 152 // the memory block was allocated by the TempMapping class. |
| 134 static TempMapping* GetMappingFromPtr(void* mem); | 153 static TempMapping* GetMappingFromPtr(void* mem); |
| 135 | 154 |
| 136 protected: | 155 protected: |
| 137 TempFile file_; | 156 TempFile file_; |
| 138 FileMapping mapping_; | 157 FileMapping mapping_; |
| 139 }; | 158 }; |
| 140 | 159 |
| 141 // An STL compatible memory allocator class that allocates memory either | 160 // An STL compatible memory allocator class that allocates memory either |
|
grt (UTC plus 2)
2011/04/05 17:10:08
Since the allocate() method now returns NULL on er
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 142 // from the heap or via a temporary file. A file allocation will be made | 161 // from the heap or via a temporary file. A file allocation will be made |
| 143 // if either the requested memory size exceeds |kMaxHeapAllocationSize| | 162 // if either the requested memory size exceeds |kMaxHeapAllocationSize| |
| 144 // or if a heap allocation fails. | 163 // or if a heap allocation fails. |
| 145 // Allocating the memory as a mapping of a temporary file solves the problem | 164 // Allocating the memory as a mapping of a temporary file solves the problem |
| 146 // that there might not be enough physical memory and pagefile to support the | 165 // that there might not be enough physical memory and pagefile to support the |
| 147 // allocation. This can happen because these resources are too small, or | 166 // allocation. This can happen because these resources are too small, or |
| 148 // already committed to other processes. Provided there is enough disk, the | 167 // already committed to other processes. Provided there is enough disk, the |
| 149 // temporary file acts like a pagefile that other processes can't access. | 168 // temporary file acts like a pagefile that other processes can't access. |
| 150 template<class T> | 169 template<class T, AllocationFailureHandler mem_failures_handler> |
|
grt (UTC plus 2)
2011/04/05 17:10:08
If you make this template<class T, AllocationFailu
tommi (sloooow) - chröme
2011/04/05 19:06:53
Yes, but afaik the style guide doesn't allow that,
| |
| 151 class MemoryAllocator { | 170 class MemoryAllocator { |
| 152 public: | 171 public: |
| 153 typedef T value_type; | 172 typedef T value_type; |
| 154 typedef value_type* pointer; | 173 typedef value_type* pointer; |
| 155 typedef value_type& reference; | 174 typedef value_type& reference; |
| 156 typedef const value_type* const_pointer; | 175 typedef const value_type* const_pointer; |
| 157 typedef const value_type& const_reference; | 176 typedef const value_type& const_reference; |
| 158 typedef size_t size_type; | 177 typedef size_t size_type; |
| 159 typedef ptrdiff_t difference_type; | 178 typedef ptrdiff_t difference_type; |
| 160 | 179 |
| 161 // Each allocation is tagged with a single byte so that we know how to | 180 // Each allocation is tagged with a single byte so that we know how to |
| 162 // deallocate it. | 181 // deallocate it. |
| 163 enum AllocationType { | 182 enum AllocationType { |
| 164 HEAP_ALLOCATION, | 183 HEAP_ALLOCATION, |
| 165 FILE_ALLOCATION, | 184 FILE_ALLOCATION, |
| 166 }; | 185 }; |
| 167 | 186 |
| 168 // 5MB is the maximum heap allocation size that we'll attempt. | 187 // 5MB is the maximum heap allocation size that we'll attempt. |
| 169 // When applying a patch for Chrome 10.X we found that at this | 188 // When applying a patch for Chrome 10.X we found that at this |
| 170 // threshold there were 17 allocations higher than this threshold | 189 // threshold there were 17 allocations higher than this threshold |
| 171 // (largest at 136MB) 10 allocations just below the threshold and 6362 | 190 // (largest at 136MB) 10 allocations just below the threshold and 6362 |
| 172 // smaller allocations. | 191 // smaller allocations. |
| 173 static const size_t kMaxHeapAllocationSize = 1024 * 1024 * 5; | 192 static const size_t kMaxHeapAllocationSize = 1024 * 1024 * 5; |
| 174 | 193 |
| 175 template<class OtherT> | 194 template<class OtherT> |
| 176 struct rebind { | 195 struct rebind { |
| 177 // convert an MemoryAllocator<T> to a MemoryAllocator<OtherT> | 196 // convert a MemoryAllocator<T> to a MemoryAllocator<OtherT> |
| 178 typedef MemoryAllocator<OtherT> other; | 197 typedef MemoryAllocator<OtherT, mem_failures_handler> other; |
| 179 }; | 198 }; |
| 180 | 199 |
| 181 MemoryAllocator() _THROW0() { | 200 MemoryAllocator() _THROW0() { |
| 182 } | 201 } |
| 183 | 202 |
| 184 // We can't use an explicit constructor here, as dictated by our style guide. | 203 // We can't use an explicit constructor here, as dictated by our style guide. |
| 185 // The implementation of basic_string in Visual Studio 2010 prevents this. | 204 // The implementation of basic_string in Visual Studio 2010 prevents this. |
| 186 MemoryAllocator(const MemoryAllocator<T>& other) _THROW0() { | 205 MemoryAllocator( // NOLINT |
| 206 const MemoryAllocator<T, mem_failures_handler>& other) _THROW0() { | |
| 187 } | 207 } |
| 188 | 208 |
| 189 template<class OtherT> | 209 template<class OtherT> |
| 190 explicit MemoryAllocator(const MemoryAllocator<OtherT>& other) _THROW0() { | 210 MemoryAllocator( // NOLINT |
| 211 const MemoryAllocator<OtherT, mem_failures_handler>& other) _THROW0() { | |
| 191 } | 212 } |
| 192 | 213 |
| 193 ~MemoryAllocator() { | 214 ~MemoryAllocator() { |
| 194 } | 215 } |
| 195 | 216 |
| 196 void deallocate(pointer ptr, size_type size) { | 217 void deallocate(pointer ptr, size_type size) { |
| 197 uint8* mem = reinterpret_cast<uint8*>(ptr); | 218 uint8* mem = reinterpret_cast<uint8*>(ptr); |
| 198 mem -= sizeof(T); | 219 mem -= sizeof(T); |
| 199 if (mem[0] == HEAP_ALLOCATION) { | 220 if (mem[0] == HEAP_ALLOCATION) { |
| 200 delete [] mem; | 221 delete [] mem; |
| 201 } else { | 222 } else { |
| 202 DCHECK_EQ(static_cast<uint8>(FILE_ALLOCATION), mem[0]); | 223 DCHECK_EQ(static_cast<uint8>(FILE_ALLOCATION), mem[0]); |
| 203 TempMapping* mapping = TempMapping::GetMappingFromPtr(mem); | 224 TempMapping* mapping = TempMapping::GetMappingFromPtr(mem); |
| 204 delete mapping; | 225 delete mapping; |
| 205 } | 226 } |
| 206 } | 227 } |
| 207 | 228 |
| 208 pointer allocate(size_type count) { | 229 pointer allocate(size_type count) { |
| 209 // We use the first byte of each allocation to mark the allocation type. | 230 // We use the first byte of each allocation to mark the allocation type. |
| 210 // However, so that the allocation is properly aligned, we allocate an | 231 // However, so that the allocation is properly aligned, we allocate an |
| 211 // extra element and then use the first byte of the first element | 232 // extra element and then use the first byte of the first element |
| 212 // to mark the allocation type. | 233 // to mark the allocation type. |
| 213 count++; | 234 count++; |
| 214 | 235 |
| 215 if (count > max_size()) | 236 if (count > max_size()) { |
| 216 throw std::length_error("overflow"); | 237 if (mem_failures_handler) |
| 238 mem_failures_handler(ERROR_INVALID_PARAMETER); | |
| 239 return NULL; | |
| 240 } | |
| 217 | 241 |
| 218 size_type bytes = count * sizeof(T); | 242 size_type bytes = count * sizeof(T); |
| 219 uint8* mem = NULL; | 243 uint8* mem = NULL; |
| 220 | 244 |
| 221 // First see if we can do this allocation on the heap. | 245 // First see if we can do this allocation on the heap. |
| 222 if (count < kMaxHeapAllocationSize) | 246 if (count < kMaxHeapAllocationSize) |
| 223 mem = new(std::nothrow) uint8[bytes]; | 247 mem = new(std::nothrow) uint8[bytes]; |
| 224 if (mem != NULL) { | 248 if (mem != NULL) { |
| 225 mem[0] = static_cast<uint8>(HEAP_ALLOCATION); | 249 mem[0] = static_cast<uint8>(HEAP_ALLOCATION); |
| 226 } else { | 250 } else { |
| 227 // If either the heap allocation failed or the request exceeds the | 251 // If either the heap allocation failed or the request exceeds the |
| 228 // max heap allocation threshold, we back the allocation with a temp file. | 252 // max heap allocation threshold, we back the allocation with a temp file. |
| 229 TempMapping* mapping = new TempMapping(); | 253 TempMapping* mapping = new(std::nothrow) TempMapping(); |
| 230 mapping->Initialize(bytes); | 254 if (!mapping && mem_failures_handler) |
| 231 mem = reinterpret_cast<uint8*>(mapping->memory()); | 255 mem_failures_handler(ERROR_OUTOFMEMORY); |
| 232 mem[0] = static_cast<uint8>(FILE_ALLOCATION); | 256 |
| 257 if (mapping && mapping->Initialize(bytes, mem_failures_handler)) { | |
| 258 mem = reinterpret_cast<uint8*>(mapping->memory()); | |
| 259 mem[0] = static_cast<uint8>(FILE_ALLOCATION); | |
| 260 } | |
| 233 } | 261 } |
| 234 return reinterpret_cast<pointer>(mem + sizeof(T)); | 262 return mem ? reinterpret_cast<pointer>(mem + sizeof(T)) : NULL; |
| 235 } | 263 } |
| 236 | 264 |
| 237 pointer allocate(size_type count, const void* hint) { | 265 pointer allocate(size_type count, const void* hint) { |
| 238 return allocate(count); | 266 return allocate(count); |
| 239 } | 267 } |
| 240 | 268 |
| 241 void construct(pointer ptr, const T& value) { | 269 void construct(pointer ptr, const T& value) { |
| 242 ::new(ptr) T(value); | 270 ::new(ptr) T(value); |
| 243 } | 271 } |
| 244 | 272 |
| 245 void destroy(pointer ptr) { | 273 void destroy(pointer ptr) { |
| 246 ptr->~T(); | 274 ptr->~T(); |
| 247 } | 275 } |
| 248 | 276 |
| 249 size_t max_size() const _THROW0() { | 277 size_t max_size() const _THROW0() { |
| 250 size_type count = static_cast<size_type>(-1) / sizeof(T); | 278 size_type count = static_cast<size_type>(-1) / sizeof(T); |
| 251 return (0 < count ? count : 1); | 279 return (0 < count ? count : 1); |
| 252 } | 280 } |
| 253 }; | 281 }; |
| 254 | 282 |
| 255 #else // OS_WIN | 283 #else // OS_WIN |
| 256 | 284 |
| 257 // On Mac, Linux, we just use the default STL allocator. | 285 // On Mac, Linux, we just use the default STL allocator. |
| 258 template<class T> | 286 template<class T> |
| 259 class MemoryAllocator : public std::allocator<T> { | 287 class MemoryAllocator : public std::allocator<T> { |
|
grt (UTC plus 2)
2011/04/05 17:10:08
This class template has different semantics than t
tommi (sloooow) - chröme
2011/04/05 19:06:53
That's intentional. The problem I'm addressing is
| |
| 260 public: | 288 public: |
| 261 }; | 289 }; |
| 262 | 290 |
| 263 #endif // OS_WIN | 291 #endif // OS_WIN |
| 264 | 292 |
|
grt (UTC plus 2)
2011/04/05 17:10:08
Add some documentation for this class and for its
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 293 template<typename T> | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
Consider:
template<typename T, class Allocator = M
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 294 class NoThrowBuffer { | |
| 295 public: | |
| 296 typedef T value_type; | |
| 297 const static size_t kAllocationFailure = 0xffffffff; | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
"static const" here and on the next line.
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 298 const static size_t kStartSize = sizeof(T) > 0xff ? 1 : 0xff / sizeof(T); | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
Why 0xff rather than 0x100?
tommi (sloooow) - chröme
2011/04/05 19:06:53
Cause it's closer to fffffuuuuuuuu... :) no real r
| |
| 299 | |
| 300 NoThrowBuffer() : buffer_(NULL), size_(0), alloc_size_(0) { | |
| 301 } | |
| 302 | |
| 303 ~NoThrowBuffer() { | |
| 304 clear(); | |
| 305 } | |
| 306 | |
| 307 void clear() { | |
| 308 if (buffer_) { | |
| 309 alloc_.deallocate(buffer_, alloc_size_); | |
| 310 buffer_ = NULL; | |
| 311 size_ = 0; | |
| 312 alloc_size_ = 0; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 bool empty() const { | |
| 317 return size_ == 0; | |
| 318 } | |
| 319 | |
| 320 CheckBool reserve(size_t size) { | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
Use WARN_UNUSED_RESULT (from base/compiler_specifi
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 321 if (failed()) | |
| 322 return false; | |
| 323 | |
| 324 if (size <= alloc_size_) | |
| 325 return true; | |
| 326 | |
| 327 if (size < kStartSize) { | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
nit: remove braces
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 328 size = kStartSize; | |
| 329 } | |
| 330 | |
| 331 T* new_buffer = alloc_.allocate(size); | |
| 332 if (!new_buffer) { | |
| 333 clear(); | |
| 334 alloc_size_ = kAllocationFailure; | |
| 335 } else { | |
| 336 if (buffer_) { | |
| 337 memcpy(new_buffer, buffer_, size_ * sizeof(T)); | |
| 338 alloc_.deallocate(buffer_, alloc_size_); | |
| 339 } | |
| 340 buffer_ = new_buffer; | |
| 341 alloc_size_ = size; | |
| 342 } | |
| 343 | |
| 344 return !failed(); | |
| 345 } | |
| 346 | |
| 347 CheckBool append(const T* data, size_t size) { | |
| 348 if (failed()) | |
| 349 return false; | |
| 350 | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
if (size > alloc_.max_size() - size_)
return fal
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 351 if (!size) | |
| 352 return true; | |
| 353 | |
| 354 if ((alloc_size_ - size_) < size) { | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
this code has a few problems with overflow. the f
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 355 size_t new_size = alloc_size_ ? (alloc_size_ * 2) : kStartSize; | |
| 356 while (new_size < size) | |
| 357 new_size *= 2; | |
| 358 if (!reserve(new_size)) | |
| 359 return false; | |
| 360 } | |
| 361 | |
| 362 memcpy(buffer_ + size_, data, size * sizeof(T)); | |
| 363 size_ += size; | |
| 364 | |
| 365 return true; | |
| 366 } | |
| 367 | |
| 368 CheckBool resize(size_t size, const T& init_value) { | |
| 369 if (size > size_) { | |
| 370 if (!reserve(size)) | |
| 371 return false; | |
| 372 for (size_t i = size_; i < size; ++i) | |
| 373 buffer_[i] = init_value; | |
| 374 } else if (size < size_) { | |
| 375 // TODO(tommi): Should we allocate a new, smaller buffer? | |
| 376 // It might simply be faster for us to don't reallocate but only | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
nit: "It might be faster for us to simply change t
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 377 // change the size. | |
| 378 } | |
| 379 | |
| 380 size_ = size; | |
| 381 | |
| 382 return true; | |
| 383 } | |
| 384 | |
| 385 CheckBool push_back(const T& item) { | |
| 386 return append(&item, 1); | |
| 387 } | |
| 388 | |
| 389 const T& back() const { | |
| 390 return buffer_[size_ - 1]; | |
| 391 } | |
| 392 | |
| 393 T& back() { | |
| 394 return buffer_[size_ - 1]; | |
| 395 } | |
| 396 | |
| 397 const T* begin() const { | |
| 398 if (!size_) | |
| 399 return NULL; | |
| 400 return &buffer_[0]; | |
| 401 } | |
| 402 | |
| 403 T* begin() { | |
| 404 if (!size_) | |
| 405 return NULL; | |
| 406 return &buffer_[0]; | |
| 407 } | |
| 408 | |
| 409 const T* end() const { | |
| 410 if (!size_) | |
| 411 return NULL; | |
| 412 return &buffer_[size_ - 1]; | |
| 413 } | |
| 414 | |
| 415 T* end() { | |
| 416 if (!size_) | |
| 417 return NULL; | |
| 418 return &buffer_[size_ - 1]; | |
| 419 } | |
| 420 | |
| 421 const T& operator[](size_t index) const { | |
| 422 return buffer_[index]; | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
DCHECK(index < size_)?
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 423 } | |
| 424 | |
| 425 T& operator[](size_t index) { | |
| 426 return buffer_[index]; | |
|
grt (UTC plus 2)
2011/04/05 17:10:08
DCHECK(index < size_)?
tommi (sloooow) - chröme
2011/04/05 19:06:53
Done.
| |
| 427 } | |
| 428 | |
| 429 size_t size() const { | |
| 430 return size_; | |
| 431 } | |
| 432 | |
| 433 T* data() const { | |
| 434 return buffer_; | |
| 435 } | |
| 436 | |
| 437 // Returns true if an allocation failure has ever occurred for this object. | |
| 438 bool failed() const { | |
| 439 return alloc_size_ == kAllocationFailure; | |
| 440 } | |
| 441 | |
| 442 protected: | |
| 443 T* buffer_; | |
| 444 size_t size_; // how much of the buffer we're using. | |
| 445 size_t alloc_size_; // how much space we have allocated. | |
| 446 #ifdef OS_WIN | |
| 447 MemoryAllocator<T, NULL> alloc_; | |
| 448 #else | |
| 449 MemoryAllocator<T> alloc_; | |
| 450 #endif | |
| 451 }; | |
| 452 | |
| 265 } // namespace courgette | 453 } // namespace courgette |
| 266 | 454 |
| 267 #endif // COURGETTE_MEMORY_ALLOCATOR_H_ | 455 #endif // COURGETTE_MEMORY_ALLOCATOR_H_ |
| OLD | NEW |