diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/core/SkSmallAllocator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/core/SkSmallAllocator.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright 2014 Google, Inc + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSmallAllocator_DEFINED +#define SkSmallAllocator_DEFINED + +#include "SkTDArray.h" +#include "SkTypes.h" + +// Used by SkSmallAllocator to call the destructor for objects it has +// allocated. +template void destroyT(void* ptr) { + static_cast(ptr)->~T(); +} + +/* + * Template class for allocating small objects without additional heap memory + * allocations. kMaxObjects is a hard limit on the number of objects that can + * be allocated using this class. After that, attempts to create more objects + * with this class will assert and return NULL. + * kTotalBytes is the total number of bytes provided for storage for all + * objects created by this allocator. If an object to be created is larger + * than the storage (minus storage already used), it will be allocated on the + * heap. This class's destructor will handle calling the destructor for each + * object it allocated and freeing its memory. + */ +template +class SkSmallAllocator : public SkNoncopyable { +public: + SkSmallAllocator() + : fStorageUsed(0) + , fNumObjects(0) + {} + + ~SkSmallAllocator() { + // Destruct in reverse order, in case an earlier object points to a + // later object. + while (fNumObjects > 0) { + fNumObjects--; + Rec* rec = &fRecs[fNumObjects]; + rec->fKillProc(rec->fObj); + // Safe to do if fObj is in fStorage, since fHeapStorage will + // point to NULL. + sk_free(rec->fHeapStorage); + } + } + + /* + * Create a new object of type T. Its lifetime will be handled by this + * SkSmallAllocator. + * Each version behaves the same but takes a different number of + * arguments. + * Note: If kMaxObjects have been created by this SkSmallAllocator, NULL + * will be returned. + */ + template + T* createT() { + void* buf = this->reserveT(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT(buf, T); + return static_cast(buf); + } + + template T* createT(const A1& a1) { + void* buf = this->reserveT(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1)); + return static_cast(buf); + } + + template + T* createT(const A1& a1, const A2& a2) { + void* buf = this->reserveT(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2)); + return static_cast(buf); + } + + template + T* createT(const A1& a1, const A2& a2, const A3& a3) { + void* buf = this->reserveT(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2, a3)); + return static_cast(buf); + } + + /* + * Reserve a specified amount of space (must be enough space for one T). + * The space will be in fStorage if there is room, or on the heap otherwise. + * Either way, this class will call ~T() in its destructor and free the heap + * allocation if necessary. + * Unlike createT(), this method will not call the constructor of T. + */ + template void* reserveT(size_t storageRequired = sizeof(T)) { + SkASSERT(fNumObjects < kMaxObjects); + SkASSERT(storageRequired >= sizeof(T)); + if (kMaxObjects == fNumObjects) { + return NULL; + } + const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed; + storageRequired = SkAlign4(storageRequired); + Rec* rec = &fRecs[fNumObjects]; + if (storageRequired > storageRemaining) { + // Allocate on the heap. Ideally we want to avoid this situation, + // but we're not sure we can catch all callers, so handle it but + // assert false in debug mode. + SkASSERT(false); + rec->fHeapStorage = sk_malloc_throw(storageRequired); + rec->fObj = static_cast(rec->fHeapStorage); + } else { + // There is space in fStorage. + rec->fHeapStorage = NULL; + SkASSERT(SkIsAlign4(fStorageUsed)); + rec->fObj = static_cast(fStorage + (fStorageUsed / 4)); + fStorageUsed += storageRequired; + } + rec->fKillProc = destroyT; + fNumObjects++; + return rec->fObj; + } + +private: + struct Rec { + void* fObj; + void* fHeapStorage; + void (*fKillProc)(void*); + }; + + // Number of bytes used so far. + size_t fStorageUsed; + // Pad the storage size to be 4-byte aligned. + uint32_t fStorage[SkAlign4(kTotalBytes) >> 2]; + uint32_t fNumObjects; + Rec fRecs[kMaxObjects]; +}; + +#endif // SkSmallAllocator_DEFINED