blob: ab14c3116836d0ac4c814825661c2332f720a20e [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_LIB_ESCHER_UTIL_BLOCK_ALLOCATOR_H_
#define SRC_UI_LIB_ESCHER_UTIL_BLOCK_ALLOCATOR_H_
#include <list>
#include <vector>
#include "src/ui/lib/escher/util/system_values.h"
namespace escher {
// A BlockAllocator allocates raw CPU data from fixed-size blocks. To minimize
// overhead, allocations are not freed individually; the Reset() method frees
// all allocations at once. Large allocations may exceed the size of a block;
// these are allocated separately (although still freed at the same time).
class BlockAllocator {
public:
explicit BlockAllocator(size_t fixed_size_block_size = 256 * 1024);
BlockAllocator(BlockAllocator&& other) = default;
void* Allocate(size_t size, size_t alignment = ESCHER_CACHE_LINE_SIZE);
template <typename T>
T* Allocate() {
static_assert(std::is_trivially_destructible<T>::value, "Type must be trivially destructible.");
return static_cast<T*>(Allocate(sizeof(T), alignof(T)));
}
template <typename T>
T* AllocateMany(size_t count) {
static_assert(std::is_trivially_destructible<T>::value, "Type must be trivially destructible.");
static_assert(sizeof(T) % alignof(T) == 0, "sizeof type must be multiple of alignof type.");
return static_cast<T*>(Allocate(count * sizeof(T), alignof(T)));
}
template <typename T>
T* AllocateInitialized(size_t count = 1) {
static_assert(std::is_trivially_destructible<T>::value, "Type must be trivially destructible.");
T* ptr = static_cast<T*>(Allocate(count * sizeof(T), alignof(T)));
for (size_t i = 0; i < count; ++i) {
new (&ptr[i]) T(); // placement new
}
return ptr;
}
// Invalidates all previously-allocated pointers. Large blocks are freed, and
// fixed-size blocks are made available for reuse.
void Reset();
private:
struct Block {
std::vector<uint8_t> bytes;
uint8_t* current_ptr;
uint8_t* start;
uint8_t* end;
// Constructor. Resizes |bytes| to proper size, and sets |start|, |end|,
// and |current_ptr| accordingly.
Block(size_t size);
void Reset() { current_ptr = start; }
};
using BlockList = std::list<Block>;
BlockList::iterator InsertLargeBlock(size_t size, size_t alignment);
BlockList::iterator ObtainNextFixedSizeBlock();
void* AllocateFromBlock(BlockList::iterator it, size_t size, size_t alignment);
const size_t fixed_size_block_size_;
BlockList fixed_size_blocks_;
BlockList::iterator current_fixed_size_block_;
BlockList large_blocks_;
public:
// For debugging/testing.
const BlockList& fixed_size_blocks() const { return fixed_size_blocks_; }
const BlockList& large_blocks() const { return large_blocks_; }
const Block& current_fixed_size_block() const { return *current_fixed_size_block_; }
};
} // namespace escher
#endif // SRC_UI_LIB_ESCHER_UTIL_BLOCK_ALLOCATOR_H_