123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #ifndef GrAllocator_DEFINED
- #define GrAllocator_DEFINED
- #include "include/core/SkTypes.h"
- #include "include/gpu/GrConfig.h"
- #include "include/gpu/GrTypes.h"
- #include "include/private/SkNoncopyable.h"
- #include "include/private/SkTArray.h"
- #include <new>
- class GrAllocator : SkNoncopyable {
- public:
- ~GrAllocator() { this->reset(); }
- /**
- * Create an allocator
- *
- * @param itemSize the size of each item to allocate
- * @param itemsPerBlock the number of items to allocate at once
- * @param initialBlock optional memory to use for the first block.
- * Must be at least itemSize*itemsPerBlock sized.
- * Caller is responsible for freeing this memory.
- */
- GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
- : fItemSize(itemSize)
- , fItemsPerBlock(itemsPerBlock)
- , fOwnFirstBlock(nullptr == initialBlock)
- , fCount(0)
- , fInsertionIndexInBlock(0) {
- SkASSERT(itemsPerBlock > 0);
- fBlockSize = fItemSize * fItemsPerBlock;
- if (fOwnFirstBlock) {
- // This force us to allocate a new block on push_back().
- fInsertionIndexInBlock = fItemsPerBlock;
- } else {
- fBlocks.push_back() = initialBlock;
- fInsertionIndexInBlock = 0;
- }
- }
- /**
- * Adds an item and returns pointer to it.
- *
- * @return pointer to the added item.
- */
- void* push_back() {
- // we always have at least one block
- if (fItemsPerBlock == fInsertionIndexInBlock) {
- fBlocks.push_back() = sk_malloc_throw(fBlockSize);
- fInsertionIndexInBlock = 0;
- }
- void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
- ++fCount;
- ++fInsertionIndexInBlock;
- return ret;
- }
- /**
- * Remove the last item, only call if count() != 0
- */
- void pop_back() {
- SkASSERT(fCount);
- SkASSERT(fInsertionIndexInBlock > 0);
- --fInsertionIndexInBlock;
- --fCount;
- if (0 == fInsertionIndexInBlock) {
- // Never delete the first block
- if (fBlocks.count() > 1) {
- sk_free(fBlocks.back());
- fBlocks.pop_back();
- fInsertionIndexInBlock = fItemsPerBlock;
- }
- }
- }
- /**
- * Removes all added items.
- */
- void reset() {
- int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
- for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
- sk_free(fBlocks[i]);
- }
- if (fOwnFirstBlock) {
- fBlocks.reset();
- // This force us to allocate a new block on push_back().
- fInsertionIndexInBlock = fItemsPerBlock;
- } else {
- fBlocks.pop_back_n(fBlocks.count() - 1);
- fInsertionIndexInBlock = 0;
- }
- fCount = 0;
- }
- /**
- * Returns the item count.
- */
- int count() const {
- return fCount;
- }
- /**
- * Is the count 0?
- */
- bool empty() const { return 0 == fCount; }
- /**
- * Access first item, only call if count() != 0
- */
- void* front() {
- SkASSERT(fCount);
- SkASSERT(fInsertionIndexInBlock > 0);
- return (char*)(fBlocks.front());
- }
- /**
- * Access first item, only call if count() != 0
- */
- const void* front() const {
- SkASSERT(fCount);
- SkASSERT(fInsertionIndexInBlock > 0);
- return (const char*)(fBlocks.front());
- }
- /**
- * Access last item, only call if count() != 0
- */
- void* back() {
- SkASSERT(fCount);
- SkASSERT(fInsertionIndexInBlock > 0);
- return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
- }
- /**
- * Access last item, only call if count() != 0
- */
- const void* back() const {
- SkASSERT(fCount);
- SkASSERT(fInsertionIndexInBlock > 0);
- return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
- }
- /**
- * Iterates through the allocator. This is faster than using operator[] when walking linearly
- * through the allocator.
- */
- class Iter {
- public:
- /**
- * Initializes the iterator. next() must be called before get().
- */
- Iter(const GrAllocator* allocator)
- : fAllocator(allocator)
- , fBlockIndex(-1)
- , fIndexInBlock(allocator->fItemsPerBlock - 1)
- , fItemIndex(-1) {}
- /**
- * Advances the iterator. Iteration is finished when next() returns false.
- */
- bool next() {
- ++fIndexInBlock;
- ++fItemIndex;
- if (fIndexInBlock == fAllocator->fItemsPerBlock) {
- ++fBlockIndex;
- fIndexInBlock = 0;
- }
- return fItemIndex < fAllocator->fCount;
- }
- /**
- * Gets the current iterator value. Call next() at least once before calling. Don't call
- * after next() returns false.
- */
- void* get() const {
- SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
- return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
- }
- private:
- const GrAllocator* fAllocator;
- int fBlockIndex;
- int fIndexInBlock;
- int fItemIndex;
- };
- /**
- * Access item by index.
- */
- void* operator[] (int i) {
- SkASSERT(i >= 0 && i < fCount);
- return (char*)fBlocks[i / fItemsPerBlock] +
- fItemSize * (i % fItemsPerBlock);
- }
- /**
- * Access item by index.
- */
- const void* operator[] (int i) const {
- SkASSERT(i >= 0 && i < fCount);
- return (const char*)fBlocks[i / fItemsPerBlock] +
- fItemSize * (i % fItemsPerBlock);
- }
- protected:
- /**
- * Set first block of memory to write into. Must be called before any other methods.
- * This requires that you have passed nullptr in the constructor.
- *
- * @param initialBlock optional memory to use for the first block.
- * Must be at least itemSize*itemsPerBlock sized.
- * Caller is responsible for freeing this memory.
- */
- void setInitialBlock(void* initialBlock) {
- SkASSERT(0 == fCount);
- SkASSERT(0 == fBlocks.count());
- SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
- fOwnFirstBlock = false;
- fBlocks.push_back() = initialBlock;
- fInsertionIndexInBlock = 0;
- }
- // For access to above function.
- template <typename T> friend class GrTAllocator;
- private:
- static const int NUM_INIT_BLOCK_PTRS = 8;
- SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true> fBlocks;
- size_t fBlockSize;
- size_t fItemSize;
- int fItemsPerBlock;
- bool fOwnFirstBlock;
- int fCount;
- int fInsertionIndexInBlock;
- typedef SkNoncopyable INHERITED;
- };
- template <typename T> class GrTAllocator;
- template <typename T> void* operator new(size_t, GrTAllocator<T>*);
- template <typename T> class GrTAllocator : SkNoncopyable {
- public:
- virtual ~GrTAllocator() { this->reset(); }
- /**
- * Create an allocator
- *
- * @param itemsPerBlock the number of items to allocate at once
- */
- explicit GrTAllocator(int itemsPerBlock)
- : fAllocator(sizeof(T), itemsPerBlock, nullptr) {}
- /**
- * Adds an item and returns it.
- *
- * @return the added item.
- */
- T& push_back() {
- void* item = fAllocator.push_back();
- SkASSERT(item);
- new (item) T;
- return *(T*)item;
- }
- T& push_back(const T& t) {
- void* item = fAllocator.push_back();
- SkASSERT(item);
- new (item) T(t);
- return *(T*)item;
- }
- template <typename... Args> T& emplace_back(Args&&... args) {
- void* item = fAllocator.push_back();
- SkASSERT(item);
- new (item) T(std::forward<Args>(args)...);
- return *(T*)item;
- }
- /**
- * Remove the last item, only call if count() != 0
- */
- void pop_back() {
- this->back().~T();
- fAllocator.pop_back();
- }
- /**
- * Removes all added items.
- */
- void reset() {
- int c = fAllocator.count();
- for (int i = 0; i < c; ++i) {
- ((T*)fAllocator[i])->~T();
- }
- fAllocator.reset();
- }
- /**
- * Returns the item count.
- */
- int count() const {
- return fAllocator.count();
- }
- /**
- * Is the count 0?
- */
- bool empty() const { return fAllocator.empty(); }
- /**
- * Access first item, only call if count() != 0
- */
- T& front() {
- return *(T*)fAllocator.front();
- }
- /**
- * Access first item, only call if count() != 0
- */
- const T& front() const {
- return *(T*)fAllocator.front();
- }
- /**
- * Access last item, only call if count() != 0
- */
- T& back() {
- return *(T*)fAllocator.back();
- }
- /**
- * Access last item, only call if count() != 0
- */
- const T& back() const {
- return *(const T*)fAllocator.back();
- }
- /**
- * Iterates through the allocator. This is faster than using operator[] when walking linearly
- * through the allocator.
- */
- class Iter {
- public:
- /**
- * Initializes the iterator. next() must be called before get() or ops * and ->.
- */
- Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
- /**
- * Advances the iterator. Iteration is finished when next() returns false.
- */
- bool next() { return fImpl.next(); }
- /**
- * Gets the current iterator value. Call next() at least once before calling. Don't call
- * after next() returns false.
- */
- T* get() const { return (T*) fImpl.get(); }
- /**
- * Convenience operators. Same rules for calling apply as get().
- */
- T& operator*() const { return *this->get(); }
- T* operator->() const { return this->get(); }
- private:
- GrAllocator::Iter fImpl;
- };
- /**
- * Access item by index.
- */
- T& operator[] (int i) {
- return *(T*)(fAllocator[i]);
- }
- /**
- * Access item by index.
- */
- const T& operator[] (int i) const {
- return *(const T*)(fAllocator[i]);
- }
- protected:
- /*
- * Set first block of memory to write into. Must be called before any other methods.
- *
- * @param initialBlock optional memory to use for the first block.
- * Must be at least size(T)*itemsPerBlock sized.
- * Caller is responsible for freeing this memory.
- */
- void setInitialBlock(void* initialBlock) {
- fAllocator.setInitialBlock(initialBlock);
- }
- private:
- friend void* operator new<T>(size_t, GrTAllocator*);
- GrAllocator fAllocator;
- typedef SkNoncopyable INHERITED;
- };
- template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
- private:
- typedef GrTAllocator<T> INHERITED;
- public:
- GrSTAllocator() : INHERITED(N) {
- this->setInitialBlock(fStorage.get());
- }
- private:
- SkAlignedSTStorage<N, T> fStorage;
- };
- template <typename T> void* operator new(size_t size, GrTAllocator<T>* allocator) {
- return allocator->fAllocator.push_back();
- }
- // Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
- // to match the op new silences warnings about missing op delete when a constructor throws an
- // exception.
- template <typename T> void operator delete(void*, GrTAllocator<T>*) {
- SK_ABORT("Invalid Operation");
- }
- #define GrNEW_APPEND_TO_ALLOCATOR(allocator_ptr, type_name, args) \
- new (allocator_ptr) type_name args
- #endif
|