/* * Copyright 2019, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_REGION_FAT_VECTOR_H #define ANDROID_REGION_FAT_VECTOR_H #include #include #include #include #include namespace android { template class InlineStdAllocator { public: struct Allocation { private: Allocation(const Allocation&) = delete; void operator=(const Allocation&) = delete; public: Allocation() {} // char array instead of T array, so memory is uninitialized, with no destructors run char array[sizeof(T) * SIZE]; bool inUse = false; }; typedef T value_type; // needed to implement std::allocator typedef T* pointer; // needed to implement std::allocator explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} ~InlineStdAllocator() {} T* allocate(size_t num, const void* = 0) { if (!mAllocation.inUse && num <= SIZE) { mAllocation.inUse = true; return static_cast(static_cast(mAllocation.array)); } else { return static_cast(static_cast(malloc(num * sizeof(T)))); } } void deallocate(pointer p, size_t) { if (p == static_cast(static_cast(mAllocation.array))) { mAllocation.inUse = false; } else { // 'free' instead of delete here - destruction handled separately free(p); } } // The STL checks that this member type is present so that // std::allocator_traits>::rebind_alloc // works. std::vector won't be able to construct an // InlineStdAllocator, because InlineStdAllocator has no // default constructor, but vector presumably doesn't rebind the allocator // because it doesn't allocate internal node types. template struct rebind { typedef InlineStdAllocator other; }; Allocation& mAllocation; }; /** * std::vector with SIZE elements preallocated into an internal buffer. * * Useful for avoiding the cost of malloc in cases where only SIZE or * fewer elements are needed in the common case. */ template class FatVector : public std::vector> { public: FatVector() : std::vector>(InlineStdAllocator(mAllocation)) { this->reserve(SIZE); } FatVector(std::initializer_list init) : std::vector>(init, InlineStdAllocator(mAllocation)) { this->reserve(SIZE); } explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } private: typename InlineStdAllocator::Allocation mAllocation; }; } // namespace android #endif // ANDROID_REGION_FAT_VECTOR_H