/* * Copyright (c) 2014 Google, Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_GROWABLE_BUFFER_H #define B2_GROWABLE_BUFFER_H #include "b2_block_allocator.h" #include #include #include /// A simple array-like container, similar to std::vector. /// If we ever start using stl, we should replace this with std::vector. template class b2GrowableBuffer { public: b2GrowableBuffer(b2BlockAllocator& allocator) : data(NULL), count(0), capacity(0), allocator(&allocator) { } b2GrowableBuffer(const b2GrowableBuffer& rhs) : data(NULL), count(rhs.count), capacity(rhs.capacity), allocator(rhs.allocator) { if (rhs.data != NULL) { data = (T*) allocator->Allocate(sizeof(T) * capacity); memcpy(data, rhs.data, sizeof(T) * count); } } ~b2GrowableBuffer() { Free(); } T& Append() { if (count >= capacity) { Grow(); } return data[count++]; } void Reserve(int32 newCapacity) { if (capacity >= newCapacity) return; // Reallocate and copy. T* newData = (T*) allocator->Allocate(sizeof(T) * newCapacity); if (data) { memcpy(newData, data, sizeof(T) * count); allocator->Free(data, sizeof(T) * capacity); } // Update pointer and capacity. capacity = newCapacity; data = newData; } void Grow() { // Double the capacity. int32 newCapacity = capacity ? 2 * capacity : b2_minParticleSystemBufferCapacity; b2Assert(newCapacity > capacity); Reserve(newCapacity); } void Free() { if (data == NULL) return; allocator->Free(data, sizeof(data[0]) * capacity); data = NULL; capacity = 0; count = 0; } void Shorten(const T* newEnd) { b2Assert(newEnd >= data); count = (int32) (newEnd - data); } T& operator[](int i) { return data[i]; } const T& operator[](int i) const { return data[i]; } T* Data() { return data; } const T* Data() const { return data; } T* Begin() { return data; } const T* Begin() const { return data; } T* End() { return &data[count]; } const T* End() const { return &data[count]; } int32 GetCount() const { return count; } void SetCount(int32 newCount) { b2Assert(0 <= newCount && newCount <= capacity); count = newCount; } int32 GetCapacity() const { return capacity; } template T* RemoveIf(UnaryPredicate pred) { T* newEnd = std::remove_if(data, data + count, pred); Shorten(newEnd); return newEnd; } template T* Unique(BinaryPredicate pred) { T* newEnd = std::unique(data, data + count, pred); Shorten(newEnd); return newEnd; } private: T* data; int32 count; int32 capacity; b2BlockAllocator* allocator; }; #endif // B2_GROWABLE_BUFFER_H