/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTDArray_DEFINED #define SkTDArray_DEFINED #include "include/private/base/SkAPI.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkTo.h" #include #include #include class SK_SPI SkTDStorage { public: explicit SkTDStorage(int sizeOfT); SkTDStorage(const void* src, int size, int sizeOfT); // Copy SkTDStorage(const SkTDStorage& that); SkTDStorage& operator= (const SkTDStorage& that); // Move SkTDStorage(SkTDStorage&& that); SkTDStorage& operator= (SkTDStorage&& that); ~SkTDStorage(); void reset(); void swap(SkTDStorage& that); // Size routines bool empty() const { return fSize == 0; } void clear() { fSize = 0; } int size() const { return fSize; } void resize(int newSize); size_t size_bytes() const { return this->bytes(fSize); } // Capacity routines int capacity() const { return fCapacity; } void reserve(int newCapacity); void shrink_to_fit(); void* data() { return fStorage; } const void* data() const { return fStorage; } // Deletion routines void erase(int index, int count); // Removes the entry at 'index' and replaces it with the last array element void removeShuffle(int index); // Insertion routines void* prepend(); void append(); void append(int count); void* append(const void* src, int count); void* insert(int index); void* insert(int index, int count, const void* src); void pop_back() { SkASSERT(fSize > 0); fSize--; } friend bool operator==(const SkTDStorage& a, const SkTDStorage& b); friend bool operator!=(const SkTDStorage& a, const SkTDStorage& b) { return !(a == b); } private: size_t bytes(int n) const { return SkToSizeT(n * fSizeOfT); } void* address(int n) { return fStorage + this->bytes(n); } // Adds delta to fSize. Crash if outside [0, INT_MAX] int calculateSizeOrDie(int delta); // Move the tail of the array defined by the indexes tailStart and tailEnd to dstIndex. The // elements at dstIndex are overwritten by the tail. void moveTail(int dstIndex, int tailStart, int tailEnd); // Copy src into the array at dstIndex. void copySrc(int dstIndex, const void* src, int count); const int fSizeOfT; std::byte* fStorage{nullptr}; int fCapacity{0}; // size of the allocation in fArray (#elements) int fSize{0}; // logical number of elements (fSize <= fCapacity) }; static inline void swap(SkTDStorage& a, SkTDStorage& b) { a.swap(b); } // SkTDArray implements a std::vector-like array for raw data-only objects that do not require // construction or destruction. The constructor and destructor for T will not be called; T objects // will always be moved via raw memcpy. Newly created T objects will contain uninitialized memory. template class SkTDArray { public: SkTDArray() : fStorage{sizeof(T)} {} SkTDArray(const T src[], int count) : fStorage{src, count, sizeof(T)} { } SkTDArray(const std::initializer_list& list) : SkTDArray(list.begin(), list.size()) {} // Copy SkTDArray(const SkTDArray& src) : SkTDArray(src.data(), src.size()) {} SkTDArray& operator=(const SkTDArray& src) { fStorage = src.fStorage; return *this; } // Move SkTDArray(SkTDArray&& src) : fStorage{std::move(src.fStorage)} {} SkTDArray& operator=(SkTDArray&& src) { fStorage = std::move(src.fStorage); return *this; } friend bool operator==(const SkTDArray& a, const SkTDArray& b) { return a.fStorage == b.fStorage; } friend bool operator!=(const SkTDArray& a, const SkTDArray& b) { return !(a == b); } void swap(SkTDArray& that) { using std::swap; swap(fStorage, that.fStorage); } bool empty() const { return fStorage.empty(); } // Return the number of elements in the array int size() const { return fStorage.size(); } // Return the total number of elements allocated. // Note: capacity() - size() gives you the number of elements you can add without causing an // allocation. int capacity() const { return fStorage.capacity(); } // return the number of bytes in the array: count * sizeof(T) size_t size_bytes() const { return fStorage.size_bytes(); } T* data() { return static_cast(fStorage.data()); } const T* data() const { return static_cast(fStorage.data()); } T* begin() { return this->data(); } const T* begin() const { return this->data(); } T* end() { return this->data() + this->size(); } const T* end() const { return this->data() + this->size(); } T& operator[](int index) { SkASSERT(index < this->size()); return this->data()[index]; } const T& operator[](int index) const { SkASSERT(index < this->size()); return this->data()[index]; } const T& back() const { SkASSERT(this->size() > 0); return this->data()[this->size() - 1]; } T& back() { SkASSERT(this->size() > 0); return this->data()[this->size() - 1]; } void reset() { fStorage.reset(); } void clear() { fStorage.clear(); } // Sets the number of elements in the array. // If the array does not have space for count elements, it will increase // the storage allocated to some amount greater than that required. // It will never shrink the storage. void resize(int count) { fStorage.resize(count); } void reserve(int n) { fStorage.reserve(n); } T* append() { fStorage.append(); return this->end() - 1; } T* append(int count) { fStorage.append(count); return this->end() - count; } T* append(int count, const T* src) { return static_cast(fStorage.append(src, count)); } T* insert(int index) { return static_cast(fStorage.insert(index)); } T* insert(int index, int count, const T* src = nullptr) { return static_cast(fStorage.insert(index, count, src)); } void remove(int index, int count = 1) { fStorage.erase(index, count); } void removeShuffle(int index) { fStorage.removeShuffle(index); } // routines to treat the array like a stack void push_back(const T& v) { this->append(); this->back() = v; } void pop_back() { fStorage.pop_back(); } void shrink_to_fit() { fStorage.shrink_to_fit(); } private: SkTDStorage fStorage; }; template static inline void swap(SkTDArray& a, SkTDArray& b) { a.swap(b); } #endif