2015-12-08 04:51:55 +08:00
|
|
|
#pragma once
|
2015-10-09 07:24:12 +08:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-08-11 15:32:46 +08:00
|
|
|
#include "utils/on_scope_exit.hpp"
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2016-12-19 02:21:29 +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>
|
2017-02-18 18:54:37 +08:00
|
|
|
class BlockAllocator {
|
|
|
|
struct Block {
|
|
|
|
Block() { data = malloc(block_size); }
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
Block(void *ptr) { data = ptr; }
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
void *data;
|
|
|
|
};
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
public:
|
|
|
|
static constexpr size_t size = block_size;
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2017-02-18 18:54:37 +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
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
~BlockAllocator() {
|
|
|
|
for (auto block : unused_) free(block.data);
|
|
|
|
unused_.clear();
|
|
|
|
for (auto block : release_) free(block.data);
|
|
|
|
release_.clear();
|
|
|
|
}
|
2016-12-19 02:21:29 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
size_t unused_size() const { return unused_.size(); }
|
2016-12-19 02:21:29 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
size_t release_size() const { return release_.size(); }
|
2016-09-16 03:19:31 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
// Returns nullptr on no memory.
|
|
|
|
void *acquire() {
|
|
|
|
if (unused_.size() == 0) unused_.emplace_back();
|
2016-09-16 03:19:31 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
auto ptr = unused_.back().data;
|
2017-08-11 15:32:46 +08:00
|
|
|
// TODO is it necessary to use OnScopeExit here? ptr is copied by value, right?
|
|
|
|
utils::OnScopeExit on_exit([this]() { unused_.pop_back(); });
|
2017-02-18 18:54:37 +08:00
|
|
|
return ptr;
|
|
|
|
}
|
2015-10-09 07:24:12 +08:00
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
void release(void *ptr) { release_.emplace_back(ptr); }
|
2016-09-16 03:19:31 +08:00
|
|
|
|
2017-02-18 18:54:37 +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
|
|
|
};
|