aco: make aco::monotonic_buffer_resource declaration visible for aco::IDSet

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29713>
This commit is contained in:
Daniel Schürmann
2023-02-10 13:55:09 +01:00
committed by Marge Bot
parent 95967c2ca0
commit 97fd5d3f33

View File

@@ -219,6 +219,165 @@ private:
size_type length{0}; //!> Size of the span
};
/*
* Light-weight memory resource which allows to sequentially allocate from
* a buffer. Both, the release() method and the destructor release all managed
* memory.
*
* The memory resource is not thread-safe.
* This class mimics std::pmr::monotonic_buffer_resource
*/
class monotonic_buffer_resource final {
public:
explicit monotonic_buffer_resource(size_t size = initial_size)
{
/* The size parameter refers to the total size of the buffer.
* The usable data_size is size - sizeof(Buffer).
*/
size = MAX2(size, minimum_size);
buffer = (Buffer*)malloc(size);
buffer->next = nullptr;
buffer->data_size = size - sizeof(Buffer);
buffer->current_idx = 0;
}
~monotonic_buffer_resource()
{
release();
free(buffer);
}
/* Delete copy-constructor and -assignment to avoid double free() */
monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
void* allocate(size_t size, size_t alignment)
{
buffer->current_idx = align(buffer->current_idx, alignment);
if (buffer->current_idx + size <= buffer->data_size) {
uint8_t* ptr = &buffer->data[buffer->current_idx];
buffer->current_idx += size;
return ptr;
}
/* create new larger buffer */
uint32_t total_size = buffer->data_size + sizeof(Buffer);
do {
total_size *= 2;
} while (total_size - sizeof(Buffer) < size);
Buffer* next = buffer;
buffer = (Buffer*)malloc(total_size);
buffer->next = next;
buffer->data_size = total_size - sizeof(Buffer);
buffer->current_idx = 0;
return allocate(size, alignment);
}
void release()
{
while (buffer->next) {
Buffer* next = buffer->next;
free(buffer);
buffer = next;
}
buffer->current_idx = 0;
}
bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; }
private:
struct Buffer {
Buffer* next;
uint32_t current_idx;
uint32_t data_size;
uint8_t data[];
};
Buffer* buffer;
static constexpr size_t initial_size = 4096;
static constexpr size_t minimum_size = 128;
static_assert(minimum_size > sizeof(Buffer));
};
/*
* Small memory allocator which wraps monotonic_buffer_resource
* in order to implement <allocator_traits>.
*
* This class mimics std::pmr::polymorphic_allocator with monotonic_buffer_resource
* as memory resource. The advantage of this specialization is the absence of
* virtual function calls and the propagation on swap, copy- and move assignment.
*/
template <typename T> class monotonic_allocator {
public:
monotonic_allocator() = delete;
monotonic_allocator(monotonic_buffer_resource& m) : memory_resource(m) {}
template <typename U>
explicit monotonic_allocator(const monotonic_allocator<U>& rhs)
: memory_resource(rhs.memory_resource)
{}
/* Memory Allocation */
T* allocate(size_t size)
{
uint32_t bytes = sizeof(T) * size;
return (T*)memory_resource.get().allocate(bytes, alignof(T));
}
/* Memory will be freed on destruction of memory_resource */
void deallocate(T* ptr, size_t size) {}
/* Implement <allocator_traits> */
using value_type = T;
template <class U> struct rebind {
using other = monotonic_allocator<U>;
};
typedef std::true_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
template <typename> friend class monotonic_allocator;
template <typename X, typename Y>
friend bool operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
template <typename X, typename Y>
friend bool operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
private:
std::reference_wrapper<monotonic_buffer_resource> memory_resource;
};
/* Necessary for <allocator_traits>. */
template <typename X, typename Y>
inline bool
operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
{
return a.memory_resource.get() == b.memory_resource.get();
}
template <typename X, typename Y>
inline bool
operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
{
return !(a == b);
}
/*
* aco::map - alias for std::map with monotonic_allocator
*
* This template specialization mimics std::pmr::map.
*/
template <class Key, class T, class Compare = std::less<Key>>
using map = std::map<Key, T, Compare, aco::monotonic_allocator<std::pair<const Key, T>>>;
/*
* aco::unordered_map - alias for std::unordered_map with monotonic_allocator
*
* This template specialization mimics std::pmr::unordered_map.
*/
template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>>
using unordered_map =
std::unordered_map<Key, T, Hash, Pred, aco::monotonic_allocator<std::pair<const Key, T>>>;
/*
* Cache-friendly set of 32-bit IDs with fast insert/erase/lookup and
* the ability to efficiently iterate over contained elements.
@@ -413,165 +572,6 @@ IDSet::Iterator::operator*() const
return id;
}
/*
* Light-weight memory resource which allows to sequentially allocate from
* a buffer. Both, the release() method and the destructor release all managed
* memory.
*
* The memory resource is not thread-safe.
* This class mimics std::pmr::monotonic_buffer_resource
*/
class monotonic_buffer_resource final {
public:
explicit monotonic_buffer_resource(size_t size = initial_size)
{
/* The size parameter refers to the total size of the buffer.
* The usable data_size is size - sizeof(Buffer).
*/
size = MAX2(size, minimum_size);
buffer = (Buffer*)malloc(size);
buffer->next = nullptr;
buffer->data_size = size - sizeof(Buffer);
buffer->current_idx = 0;
}
~monotonic_buffer_resource()
{
release();
free(buffer);
}
/* Delete copy-constructor and -assignment to avoid double free() */
monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
void* allocate(size_t size, size_t alignment)
{
buffer->current_idx = align(buffer->current_idx, alignment);
if (buffer->current_idx + size <= buffer->data_size) {
uint8_t* ptr = &buffer->data[buffer->current_idx];
buffer->current_idx += size;
return ptr;
}
/* create new larger buffer */
uint32_t total_size = buffer->data_size + sizeof(Buffer);
do {
total_size *= 2;
} while (total_size - sizeof(Buffer) < size);
Buffer* next = buffer;
buffer = (Buffer*)malloc(total_size);
buffer->next = next;
buffer->data_size = total_size - sizeof(Buffer);
buffer->current_idx = 0;
return allocate(size, alignment);
}
void release()
{
while (buffer->next) {
Buffer* next = buffer->next;
free(buffer);
buffer = next;
}
buffer->current_idx = 0;
}
bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; }
private:
struct Buffer {
Buffer* next;
uint32_t current_idx;
uint32_t data_size;
uint8_t data[];
};
Buffer* buffer;
static constexpr size_t initial_size = 4096;
static constexpr size_t minimum_size = 128;
static_assert(minimum_size > sizeof(Buffer));
};
/*
* Small memory allocator which wraps monotonic_buffer_resource
* in order to implement <allocator_traits>.
*
* This class mimics std::pmr::polymorphic_allocator with monotonic_buffer_resource
* as memory resource. The advantage of this specialization is the absence of
* virtual function calls and the propagation on swap, copy- and move assignment.
*/
template <typename T> class monotonic_allocator {
public:
monotonic_allocator() = delete;
monotonic_allocator(monotonic_buffer_resource& m) : memory_resource(m) {}
template <typename U>
explicit monotonic_allocator(const monotonic_allocator<U>& rhs)
: memory_resource(rhs.memory_resource)
{}
/* Memory Allocation */
T* allocate(size_t size)
{
uint32_t bytes = sizeof(T) * size;
return (T*)memory_resource.get().allocate(bytes, alignof(T));
}
/* Memory will be freed on destruction of memory_resource */
void deallocate(T* ptr, size_t size) {}
/* Implement <allocator_traits> */
using value_type = T;
template <class U> struct rebind {
using other = monotonic_allocator<U>;
};
typedef std::true_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
template <typename> friend class monotonic_allocator;
template <typename X, typename Y>
friend bool operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
template <typename X, typename Y>
friend bool operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
private:
std::reference_wrapper<monotonic_buffer_resource> memory_resource;
};
/* Necessary for <allocator_traits>. */
template <typename X, typename Y>
inline bool
operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
{
return a.memory_resource.get() == b.memory_resource.get();
}
template <typename X, typename Y>
inline bool
operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
{
return !(a == b);
}
/*
* aco::map - alias for std::map with monotonic_allocator
*
* This template specialization mimics std::pmr::map.
*/
template <class Key, class T, class Compare = std::less<Key>>
using map = std::map<Key, T, Compare, aco::monotonic_allocator<std::pair<const Key, T>>>;
/*
* aco::unordered_map - alias for std::unordered_map with monotonic_allocator
*
* This template specialization mimics std::pmr::unordered_map.
*/
template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>>
using unordered_map =
std::unordered_map<Key, T, Hash, Pred, aco::monotonic_allocator<std::pair<const Key, T>>>;
/*
* Helper class for a integer/bool (access_type) packed into
* a bigger integer (data_type) with an offset and size.