diff options
author | Mauro Sardara <msardara@cisco.com> | 2020-02-21 11:52:28 +0100 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2020-02-26 13:19:16 +0100 |
commit | f4433f28b509a9f67ca85d79000ccf9c2f4b7a24 (patch) | |
tree | 0f754bc9d8222f3ace11849165753acd85be3b38 /libtransport/src/utils/memory_pool_allocator.h | |
parent | 0e7669445b6be1163189521eabed7dd0124043c8 (diff) |
[HICN-534] Major rework on libtransport organization
Change-Id: I361b83a18b4fd59be136d5f0817fc28e17e89884
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Diffstat (limited to 'libtransport/src/utils/memory_pool_allocator.h')
-rw-r--r-- | libtransport/src/utils/memory_pool_allocator.h | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/libtransport/src/utils/memory_pool_allocator.h b/libtransport/src/utils/memory_pool_allocator.h new file mode 100644 index 000000000..adc1443ad --- /dev/null +++ b/libtransport/src/utils/memory_pool_allocator.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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.sudo make instamake install + */ + +#pragma once + +#include <memory> + +namespace utils { + +template <class T, std::size_t growSize = 1024> +class MemoryPool { + struct Block { + Block *next; + }; + + class Buffer { + static const std::size_t blockSize = sizeof(T) > sizeof(Block) + ? sizeof(T) + : sizeof(Block); + uint8_t data[blockSize * growSize]; + + public: + Buffer *const next; + + Buffer(Buffer *next) : next(next) {} + + T *getBlock(std::size_t index) { + return reinterpret_cast<T *>(&data[blockSize * index]); + } + }; + + Block *firstFreeBlock = nullptr; + Buffer *firstBuffer = nullptr; + std::size_t bufferedBlocks = growSize; + + public: + MemoryPool() = default; + MemoryPool(MemoryPool &&memoryPool) = delete; + MemoryPool(const MemoryPool &memoryPool) = delete; + MemoryPool operator=(MemoryPool &&memoryPool) = delete; + MemoryPool operator=(const MemoryPool &memoryPool) = delete; + + ~MemoryPool() { + while (firstBuffer) { + Buffer *buffer = firstBuffer; + firstBuffer = buffer->next; + delete buffer; + } + } + + T *allocate() { + if (firstFreeBlock) { + Block *block = firstFreeBlock; + firstFreeBlock = block->next; + return reinterpret_cast<T *>(block); + } + + if (bufferedBlocks >= growSize) { + firstBuffer = new Buffer(firstBuffer); + bufferedBlocks = 0; + } + + return firstBuffer->getBlock(bufferedBlocks++); + } + + void deallocate(T *pointer) { + Block *block = reinterpret_cast<Block *>(pointer); + block->next = firstFreeBlock; + firstFreeBlock = block; + } +}; + +template <class T, std::size_t growSize = 1024> +class Allocator : private MemoryPool<T, growSize> { +#ifdef _WIN32 + Allocator *copyAllocator; + std::allocator<T> *rebindAllocator = nullptr; +#endif + + public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + + template <class U> + struct rebind { + typedef Allocator<U, growSize> other; + }; + +#ifdef _WIN32 + Allocator() = default; + + Allocator(Allocator &allocator) : copyAllocator(&allocator) {} + + template <class U> + Allocator(const Allocator<U, growSize> &other) { + if (!std::is_same<T, U>::value) rebindAllocator = new std::allocator<T>(); + } + + ~Allocator() { delete rebindAllocator; } +#endif + + pointer allocate(size_type n, const void *hint = 0) { +#ifdef _WIN32 + if (copyAllocator) return copyAllocator->allocate(n, hint); + + if (rebindAllocator) return rebindAllocator->allocate(n, hint); +#endif + + if (n != 1 || hint) throw std::bad_alloc(); + + return MemoryPool<T, growSize>::allocate(); + } + + void deallocate(pointer p, size_type n) { +#ifdef _WIN32 + if (copyAllocator) { + copyAllocator->deallocate(p, n); + return; + } + + if (rebindAllocator) { + rebindAllocator->deallocate(p, n); + return; + } +#endif + + MemoryPool<T, growSize>::deallocate(p); + } + + void construct(pointer p, const_reference val) { new (p) T(val); } + + void destroy(pointer p) { p->~T(); } +}; + +}
\ No newline at end of file |