1
0
Fork 0
arangodb/lib/Basics/FixedSizeAllocator.h

168 lines
4.5 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_BASICS_FIXED_SIZE_ALLOCATOR_H
#define ARANGODB_BASICS_FIXED_SIZE_ALLOCATOR_H 1
#include "Basics/Common.h"
namespace arangodb {
class FixedSizeAllocator {
private:
class MemoryBlock {
public:
MemoryBlock(MemoryBlock const&) = delete;
MemoryBlock& operator=(MemoryBlock const&) = delete;
MemoryBlock(size_t itemSize, size_t nrItems)
: _itemSize(itemSize), _nrAlloc(nrItems), _nrUsed(0), _alloc(nullptr), _data(nullptr) {
_alloc = new char[(itemSize * nrItems) + 64];
// adjust to cache line offset (assumed to be 64 bytes)
_data = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(_alloc) + 63) &
~((uintptr_t)0x3fu));
TRI_ASSERT(reinterpret_cast<uintptr_t>(_data) % sizeof(void*) == 0);
}
MemoryBlock(MemoryBlock&& other) noexcept
: _itemSize(other._itemSize),
_nrAlloc(other._nrAlloc),
_nrUsed(other._nrUsed),
_alloc(other._alloc),
_data(other._data) {
other._nrAlloc = 0;
other._nrUsed = 0;
other._alloc = nullptr;
other._data = nullptr;
}
MemoryBlock& operator=(MemoryBlock&& other) noexcept {
if (this != &other) {
TRI_ASSERT(_itemSize == other._itemSize);
delete[] _alloc;
_nrAlloc = other._nrAlloc;
_nrUsed = other._nrUsed;
_alloc = other._alloc;
_data = other._data;
other._nrAlloc = 0;
other._nrUsed = 0;
other._alloc = nullptr;
other._data = nullptr;
}
return *this;
}
~MemoryBlock() { delete[] _alloc; }
void* next() {
TRI_ASSERT(_nrUsed < _nrAlloc);
return static_cast<void*>(_data + (_itemSize * _nrUsed++));
}
inline bool full() const { return _nrUsed == _nrAlloc; }
size_t memoryUsage() const {
return (_data - _alloc) + _itemSize * _nrAlloc;
}
private:
size_t const _itemSize;
size_t _nrAlloc;
size_t _nrUsed;
char* _alloc;
char* _data;
};
public:
FixedSizeAllocator(FixedSizeAllocator const&) = delete;
FixedSizeAllocator& operator=(FixedSizeAllocator const&) = delete;
explicit FixedSizeAllocator(size_t itemSize)
: _itemSize(itemSize), _freelist(nullptr) {
_blocks.reserve(4);
#ifndef TRI_UNALIGNED_ACCESS
// align _itemSize to a multiple of sizeof(void*) on system that require it
_itemSize +=
(_itemSize % sizeof(void*) == 0 ? 0 : sizeof(void*) - _itemSize % sizeof(void*));
#endif
}
~FixedSizeAllocator() {}
void* allocate() {
if (_freelist != nullptr) {
void* element = _freelist;
_freelist = *reinterpret_cast<void**>(_freelist);
return element;
}
if (_blocks.empty() || _blocks.back()->full()) {
allocateBlock();
}
TRI_ASSERT(!_blocks.empty());
TRI_ASSERT(!_blocks.back()->full());
return _blocks.back()->next();
}
void deallocateAll() {
_blocks.clear();
_freelist = nullptr;
}
void deallocate(void* value) noexcept {
*reinterpret_cast<void**>(value) = _freelist;
_freelist = value;
}
size_t memoryUsage() const {
size_t total = 0;
for (auto const& it : _blocks) {
total += it->memoryUsage();
}
return total;
}
private:
void allocateBlock() {
size_t const size = 128 << (std::min)(size_t(8), _blocks.size());
auto block = std::make_unique<MemoryBlock>(_itemSize, size);
_blocks.emplace_back(std::move(block));
}
std::vector<std::unique_ptr<MemoryBlock>> _blocks;
size_t _itemSize;
void* _freelist;
};
} // namespace arangodb
#endif