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:

committed by
Marge Bot

parent
95967c2ca0
commit
97fd5d3f33
@@ -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.
|
||||
|
Reference in New Issue
Block a user