memgraph/poc/memory/block_allocator.hpp

58 lines
1.4 KiB
C++
Raw Normal View History

#pragma once
2015-10-09 07:24:12 +08:00
#include <memory>
#include <vector>
#include "utils/on_scope_exit.hpp"
2015-10-09 07:24:12 +08:00
/* @brief Allocates blocks of block_size and stores
* the pointers on allocated blocks inside a vector.
*/
2015-10-09 07:24:12 +08:00
template <size_t block_size>
class BlockAllocator {
struct Block {
Block() { data = malloc(block_size); }
2015-10-09 07:24:12 +08:00
Block(void *ptr) { data = ptr; }
2015-10-09 07:24:12 +08:00
void *data;
};
2015-10-09 07:24:12 +08:00
public:
static constexpr size_t size = block_size;
2015-10-09 07:24:12 +08:00
BlockAllocator(size_t capacity = 0) {
for (size_t i = 0; i < capacity; ++i) unused_.emplace_back();
}
2015-10-09 07:24:12 +08:00
~BlockAllocator() {
for (auto block : unused_) free(block.data);
unused_.clear();
for (auto block : release_) free(block.data);
release_.clear();
}
size_t unused_size() const { return unused_.size(); }
size_t release_size() const { return release_.size(); }
2016-09-16 03:19:31 +08:00
// Returns nullptr on no memory.
void *acquire() {
if (unused_.size() == 0) unused_.emplace_back();
2016-09-16 03:19:31 +08:00
auto ptr = unused_.back().data;
// TODO is it necessary to use OnScopeExit here? ptr is copied by value, right?
utils::OnScopeExit on_exit([this]() { unused_.pop_back(); });
return ptr;
}
2015-10-09 07:24:12 +08:00
void release(void *ptr) { release_.emplace_back(ptr); }
2016-09-16 03:19:31 +08:00
private:
// TODO: try implement with just one vector
// but consecutive acquire release calls should work
// TODO: measure first!
std::vector<Block> unused_;
std::vector<Block> release_;
2015-10-09 07:24:12 +08:00
};