mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-11-08 10:09:16 +00:00
Adds AllocatorAdapter written against C++20
This commit is contained in:
2 files changed
+171
No files matched your search
@@ -0,0 +1,89 @@
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_PS_ALLOCATORADAPTER
|
||||
#define INCLUDED_PS_ALLOCATORADAPTER
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace PS::Memory
|
||||
{
|
||||
|
||||
/**
|
||||
* Provides a way to use untyped allocators like LinearAllocator for
|
||||
* containers. This allocator adapter must not outlive the target
|
||||
* allocator. A client must not mix adapters with different
|
||||
* allocators.
|
||||
*
|
||||
* It provides a basic STL allocator interface. It allows to use a stateful
|
||||
* allocator:
|
||||
*
|
||||
* std::vector<Type, PS::Memory::AllocatorAdapter<Type, PS::Memory::ScopedLinearAllocator>>
|
||||
*
|
||||
* @see ScopedLinearAllocator
|
||||
*/
|
||||
template<typename T, typename Allocator>
|
||||
class AllocatorAdapter
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
// We don't need runtime checks and per-element copies for containers
|
||||
// when we have a unique allocator (means no mixing different allocators).
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using propagate_on_container_swap = std::true_type;
|
||||
using is_always_equal = std::false_type;
|
||||
|
||||
template<typename OtherT>
|
||||
struct rebind
|
||||
{
|
||||
using other = AllocatorAdapter<OtherT, Allocator>;
|
||||
};
|
||||
|
||||
constexpr AllocatorAdapter(Allocator& allocator) noexcept : m_Allocator(std::addressof(allocator)) {}
|
||||
template<typename OtherT>
|
||||
constexpr AllocatorAdapter(const AllocatorAdapter<OtherT, Allocator>& allocatorAdapter) noexcept : m_Allocator(allocatorAdapter.m_Allocator) {}
|
||||
|
||||
[[nodiscard]] constexpr T* allocate(std::size_t n)
|
||||
{
|
||||
return static_cast<T*>(m_Allocator->allocate(n * sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
constexpr void deallocate(T* ptr, std::size_t n)
|
||||
{
|
||||
m_Allocator->deallocate(static_cast<void*>(ptr), n * sizeof(T));
|
||||
}
|
||||
|
||||
template<typename OtherT>
|
||||
constexpr bool operator==(const AllocatorAdapter<OtherT, Allocator>& other) const noexcept
|
||||
{
|
||||
return m_Allocator == other.m_Allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename OtherT, typename OtherAllocator> friend class AllocatorAdapter;
|
||||
|
||||
// A pointer to make it moveable.
|
||||
Allocator* m_Allocator{nullptr};
|
||||
};
|
||||
|
||||
} // namespace PS::Memory
|
||||
|
||||
#endif // INCLUDED_PS_ALLOCATORADAPTER
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/memory/AllocatorAdapter.h"
|
||||
#include "ps/memory/LinearAllocator.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <scoped_allocator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class TestAllocatorAdapter : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
using Scoped = std::scoped_allocator_adaptor<
|
||||
PS::Memory::AllocatorAdapter<T, PS::Memory::LinearAllocator>>;
|
||||
|
||||
void test_move()
|
||||
{
|
||||
PS::Memory::LinearAllocator allocator{16, 1024};
|
||||
|
||||
std::vector<int, PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>> v1{
|
||||
PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>{allocator}};
|
||||
v1.assign(10, 1);
|
||||
|
||||
std::vector<int, PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>> v2{
|
||||
PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>{allocator}};
|
||||
|
||||
const std::size_t allocatedSize{allocator.GetSize()};
|
||||
v2 = std::move(v1);
|
||||
TS_ASSERT_EQUALS(allocatedSize, allocator.GetSize());
|
||||
}
|
||||
|
||||
void test_swap()
|
||||
{
|
||||
PS::Memory::LinearAllocator allocator{16, 1024};
|
||||
|
||||
std::vector<int, PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>> v1{
|
||||
PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>{allocator}};
|
||||
v1.assign(10, 1);
|
||||
|
||||
std::vector<int, PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>> v2{
|
||||
PS::Memory::AllocatorAdapter<int, PS::Memory::LinearAllocator>{allocator}};
|
||||
|
||||
const std::size_t allocatedSize{allocator.GetSize()};
|
||||
std::swap(v1, v2);
|
||||
TS_ASSERT_EQUALS(allocatedSize, allocator.GetSize());
|
||||
}
|
||||
|
||||
void test_nested_containers()
|
||||
{
|
||||
PS::Memory::LinearAllocator allocator{16, 4096};
|
||||
|
||||
using Vector = std::vector<int, Scoped<int>>;
|
||||
using Map = std::map<int, Vector, std::less<>, Scoped<std::pair<const int, Vector>>>;
|
||||
|
||||
Map complexContainer(Map::allocator_type{allocator});
|
||||
complexContainer[42].assign(10, 1);
|
||||
TS_ASSERT_EQUALS(complexContainer.size(), 1);
|
||||
TS_ASSERT_EQUALS(complexContainer[42].size(), 10);
|
||||
TS_ASSERT_EQUALS(complexContainer[42][0], 1);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user