Removes legacy allocator functionality from lib

This commit is contained in:
Vladislav Belov committed 2026-10-22 23:22:37 +02:00
1 parent 3d8a808b21
commit 750fbe44bd
7 files changed
-637

No files matched your search

-164
View File
@@ -1,164 +0,0 @@
/* Copyright (C) 2026 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_ALLOCATORS_DYNAMIC_ARENA
#define INCLUDED_ALLOCATORS_DYNAMIC_ARENA
#include "lib/bits.h"
#include "lib/code_annotation.h"
#include "lib/debug.h"
#include <cstdint>
#include <cstdlib>
#include <new> // bad_alloc
#include <utility>
#include <vector>
namespace Allocators {
/**
* 'Blind' memory allocator. Characteristics:
* - grows dynamically, and linearily, by BLOCK_SIZE
* - no reallocations, pointers remain valid
* - can allocate objects up to BLOCK_SIZE in size
* - can handle any aligment (up to BLOCK_SIZE)
* - Doesn't de-allocate unless cleared or destroyed.
*/
template<size_t BLOCK_SIZE>
class DynamicArena
{
protected:
class Block
{
public:
Block()
{
m_Data = static_cast<uint8_t*>(
std::malloc(BLOCK_SIZE * sizeof(uint8_t)));
if (!m_Data)
{
debug_warn("DynamicArena failed to allocate chunk");
throw std::bad_alloc();
}
}
~Block()
{
std::free(static_cast<void*>(m_Data));
}
Block(const Block& other) = delete;
Block& operator=(const Block& other) = delete;
Block(Block&& other)
: m_Size(other.m_Size), m_Data(other.m_Data)
{
other.m_Size = 0;
other.m_Data = nullptr;
}
Block& operator=(Block&& other)
{
if (&other == this)
return *this;
Block tmp(std::move(other));
swap(*this, tmp);
return *this;
}
friend void swap(Block& lhs, Block& rhs)
{
using std::swap;
swap(lhs.m_Size, rhs.m_Size);
swap(lhs.m_Data, rhs.m_Data);
}
bool Available(size_t n, size_t alignment) const
{
return n + ROUND_UP(m_Size, alignment) <= BLOCK_SIZE;
}
uint8_t* Allocate(size_t n, size_t alignment)
{
m_Size = ROUND_UP(m_Size, alignment);
uint8_t* ptr = &m_Data[m_Size];
m_Size += n;
return ptr;
}
private:
size_t m_Size = 0;
uint8_t* m_Data = nullptr;
};
NONCOPYABLE(DynamicArena);
public:
DynamicArena()
{
m_Blocks.reserve(16);
AllocateNewBlock();
};
void AllocateNewBlock()
{
m_Blocks.emplace_back();
}
void* allocate(size_t n, size_t alignment)
{
// Safely handle zero-sized allocations (happens with GCC STL - see Issue #909).
if (n == 0)
n = 1;
if (n > BLOCK_SIZE)
{
debug_warn("DynamicArena cannot allocate more than chunk size");
throw std::bad_alloc();
}
if (!m_Blocks.back().Available(n, alignment))
AllocateNewBlock();
return reinterpret_cast<void*>(m_Blocks.back().Allocate(n, alignment));
}
void deallocate(void*, size_t)
{
// ignored
}
void clear()
{
m_Blocks.clear();
AllocateNewBlock();
}
protected:
std::vector<Block> m_Blocks;
};
} // namespace Allocators
#endif // INCLUDED_ALLOCATORS_DYNAMIC_ARENA
-129
View File
@@ -1,129 +0,0 @@
/* Copyright (C) 2025 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_STL_ALLOCATORS
#define INCLUDED_STL_ALLOCATORS
#include <cstddef>
#include <memory>
#include <type_traits>
/**
* Adapt a 0 A.D.-style allocator for usage in STL containers.
* Use 'Backend' as an underlying allocator.
*/
template<typename T, class Backend>
class STLAllocator
{
template<typename A, class B>
friend class STLAllocator;
public:
using value_type = T;
using pointer = T*;
using is_always_equal = std::false_type;
STLAllocator() : allocator(std::make_shared<Backend>())
{
}
template<typename V>
STLAllocator(const STLAllocator<V, Backend>& proxy) : allocator(proxy.allocator)
{
}
template<typename V>
struct rebind
{
using other = STLAllocator<V, Backend>;
};
T* allocate(size_t n)
{
return static_cast<T*>(allocator->allocate(n * sizeof(T), alignof(T)));
}
void deallocate(T* ptr, const size_t n)
{
return allocator->deallocate(static_cast<void*>(ptr), n * sizeof(T));
}
private:
std::shared_ptr<Backend> allocator;
};
/**
* Proxies allocation to another allocator.
* This allows a single allocator to serve multiple STL containers.
*/
template<typename T, class Backend>
class ProxyAllocator
{
template<typename A, class B>
friend class ProxyAllocator;
public:
using value_type = T;
using pointer = T*;
using is_always_equal = std::false_type;
ProxyAllocator(Backend& alloc) : allocator(alloc)
{
}
template<typename V>
ProxyAllocator(const ProxyAllocator<V, Backend>& proxy) : allocator(proxy.allocator)
{
}
template<typename V>
struct rebind
{
using other = ProxyAllocator<V, Backend>;
};
T* allocate(size_t n)
{
return static_cast<T*>(allocator.allocate(n * sizeof(T), alignof(T)));
}
void deallocate(T* ptr, const size_t n)
{
return allocator.deallocate(static_cast<void*>(ptr), n * sizeof(T));
}
template<typename V>
bool operator==(const ProxyAllocator<V, Backend>& other) const
{
return std::addressof(allocator) == std::addressof(other.allocator);
}
template<typename V>
bool operator!=(const ProxyAllocator<V, Backend>& other) const
{
return std::addressof(allocator) != std::addressof(other.allocator);
}
private:
Backend& allocator;
};
#endif // INCLUDED_STL_ALLOCATORS
-76
View File
@@ -1,76 +0,0 @@
/* Copyright (C) 2025 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_ALLOCATORS_ALLOCATOR_CHECKER
#define INCLUDED_ALLOCATORS_ALLOCATOR_CHECKER
#include "lib/debug.h"
#include "lib/status.h"
#include <cstddef>
#include <map>
#include <utility>
/**
* allocator test rig.
* call from each allocator operation to sanity-check them.
* should only be used during debug mode due to serious overhead.
**/
class AllocatorChecker
{
public:
void OnAllocate(void* p, size_t size)
{
const Allocs::value_type item = std::make_pair(p, size);
std::pair<Allocs::iterator, bool> ret = allocs.insert(item);
ENSURE(ret.second == true); // wasn't already in map
}
void OnDeallocate(void* p, size_t size)
{
Allocs::iterator it = allocs.find(p);
if(it == allocs.end())
DEBUG_WARN_ERR(ERR::LOGIC); // freeing invalid pointer
else
{
// size must match what was passed to OnAllocate
const size_t allocated_size = it->second;
ENSURE(size == allocated_size);
allocs.erase(it);
}
}
/**
* allocator is resetting itself, i.e. wiping out all allocs.
**/
void OnClear()
{
allocs.clear();
}
private:
typedef std::map<void*, size_t> Allocs;
Allocs allocs;
};
#endif // #ifndef INCLUDED_ALLOCATORS_ALLOCATOR_CHECKER
-101
View File
@@ -1,101 +0,0 @@
/* Copyright (C) 2025 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef INCLUDED_ALLOCATORS_OVERRUN_PROTECTOR
#define INCLUDED_ALLOCATORS_OVERRUN_PROTECTOR
#include "lib/code_annotation.h"
#include "lib/config2.h" // CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
/**
OverrunProtector wraps an arbitrary object in isolated page(s) and
can detect inadvertent writes to it. this is useful for
tracking down memory overruns.
the basic idea is to require users to request access to the object and
notify us when done; memory access permission is temporarily granted.
(similar in principle to Software Transaction Memory).
since this is quite slow, the protection is disabled unless
CONFIG2_ALLOCATORS_OVERRUN_PROTECTION == 1; this avoids having to remove the
wrapper code in release builds and re-write when looking for overruns.
example usage:
OverrunProtector\<T\> wrapper;
..
T* p = wrapper.get(); // unlock, make ready for use
if(!p) // wrapper's one-time alloc of a T-
abort(); // instance had failed - can't continue.
DoSomethingWith(p); // (read/write access)
wrapper.lock(); // disallow further access until next .get()
..
**/
template<class T> class OverrunProtector
{
NONCOPYABLE(OverrunProtector); // const member
public:
OverrunProtector()
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
: object(new(vm::Allocate(sizeof(T))) T())
#else
: object(new T())
#endif
{
lock();
}
~OverrunProtector()
{
unlock();
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
object->~T(); // call dtor (since we used placement new)
vm::Free(object, sizeof(T));
#else
delete object;
#endif
}
T* get() const
{
unlock();
return object;
}
void lock() const
{
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
vm::Protect(object, sizeof(T), PROT_NONE);
#endif
}
private:
void unlock() const
{
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
vm::Protect(object, sizeof(T), PROT_READ|PROT_WRITE);
#endif
}
T* const object;
};
#endif // #ifndef INCLUDED_ALLOCATORS_OVERRUN_PROTECTOR
@@ -1,75 +0,0 @@
/* Copyright (C) 2026 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "lib/self_test.h"
#include "lib/allocators/DynamicArena.h"
class TestDynamicArena : public CxxTest::TestSuite
{
public:
void test_allocate()
{
Allocators::DynamicArena<100> testArena;
std::uint8_t* p = static_cast<std::uint8_t*>(testArena.allocate(10, 1));
TS_ASSERT(p != nullptr);
void* p2 = testArena.allocate(10, 1);
TS_ASSERT(p + 10 == p2);
void* p3 = testArena.allocate(80, 1);
TS_ASSERT(p + 20 == p3);
void* p4 = testArena.allocate(100, 1);
TS_ASSERT(p4 != nullptr);
void* p5 = testArena.allocate(1, 1);
TS_ASSERT(p5 != nullptr);
void* p6 = testArena.allocate(100, 1);
TS_ASSERT(p6 != nullptr);
void* p7 = testArena.allocate(0, 1);
TS_ASSERT(p7 != nullptr);
}
void test_alignment()
{
Allocators::DynamicArena<100> testArena;
std::uint8_t* p = static_cast<std::uint8_t*>(testArena.allocate(4, 1));
TS_ASSERT(p != nullptr);
std::uint8_t* p2 = static_cast<std::uint8_t*>(testArena.allocate(1, 8));
TS_ASSERT_EQUALS(p + 8, p2);
p2 = static_cast<std::uint8_t*>(testArena.allocate(1, 8));
TS_ASSERT_EQUALS(p + 16, p2);
p2 = static_cast<std::uint8_t*>(testArena.allocate(1, 8));
TS_ASSERT_EQUALS(p + 24, p2);
p2 = static_cast<std::uint8_t*>(testArena.allocate(1, 2));
TS_ASSERT_EQUALS(p + 26, p2);
p2 = static_cast<std::uint8_t*>(testArena.allocate(1, 8));
TS_ASSERT_EQUALS(p + 32, p2);
}
};
@@ -1,82 +0,0 @@
/* Copyright (C) 2025 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "lib/self_test.h"
#include "lib/allocators/DynamicArena.h"
#include "lib/allocators/STLAllocators.h"
#include <functional>
#include <map>
#include <string_view>
#include <unordered_map>
#include <vector>
class TestSTLAllocators : public CxxTest::TestSuite
{
public:
struct SomeData
{
SomeData(int) {};
int padding[10];
};
template<template<typename... Args> typename Alloc, typename D>
using Allocator = Alloc<D, Allocators::DynamicArena<4096>>;
template<typename K, typename V, template<typename... Args> typename Alloc>
using Map = std::map<K, V, std::less<K>, Allocator<Alloc, typename std::map<K, V>::value_type>>;
template<typename K, typename V, template<typename... Args> typename Alloc>
using UMap = std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, Allocator<Alloc, typename std::unordered_map<K, V>::value_type>>;
void test_CustomAllocator()
{
Map<int, SomeData, STLAllocator> map;
UMap<int, SomeData, STLAllocator> umap;
std::vector<SomeData, STLAllocator<SomeData, Allocators::DynamicArena<4096>>> vec;
map.emplace(4, 5);
umap.emplace(4, 5);
vec.emplace_back(5);
map.clear();
umap.clear();
vec.clear();
}
void test_ProxyAllocator()
{
Allocators::DynamicArena<4096> arena;
Map<int, SomeData, ProxyAllocator> map(arena);
UMap<int, SomeData, ProxyAllocator> umap(arena);
std::vector<SomeData, Allocator<ProxyAllocator, SomeData>> vec(arena);
map.emplace(4, 5);
umap.emplace(4, 5);
vec.emplace_back(5);
map.clear();
umap.clear();
vec.clear();
}
};
-10
View File
@@ -36,16 +36,6 @@
# define CONFIG2_DAP_INTERFACE 1
#endif // !CONFIG2_DAP_INTERFACE
// this enables/disables the actual checking done by OverrunProtector
// (quite slow, entailing mprotect() before/after each access).
// define to 1 here or in the relevant module if you suspect mem corruption.
// we provide this option because OverrunProtector requires some changes to
// the object being wrapped, and we want to leave those intact but not
// significantly slow things down except when needed.
#ifndef CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
# define CONFIG2_ALLOCATORS_OVERRUN_PROTECTION 0
#endif
#ifndef CONFIG2_FILE_ENABLE_AIO
// work around a bug introduced in Linux 2.6.38
// (http://www.wildfiregames.com/forum/index.php?showtopic=14561&view=findpost&p=217710)