p2p/stingray_sdk/plugin_foundation/allocator.h
Lucas Schwiderski 2c9ce46dd2
chore: Rework project structure
There likely won't be much need for multiple separate crates.
2023-05-26 23:42:01 +02:00

109 lines
3.3 KiB
C++

#pragma once
#include "../engine_plugin_api/plugin_api.h"
#define _XKEYCHECK_H
#define alignof(x) __alignof(x)
namespace stingray_plugin_foundation {
// Abstract base class for allocators.
//
// Allocators can be thread-safe or not, see the separate documentation for each
// alloactor.
class Allocator
{
Allocator(const Allocator &);
Allocator & operator=(const Allocator &);
public:
static const int DEFAULT_ALIGN = 4;
Allocator() {}
virtual ~Allocator() {}
// Convenience method for allocating when you don't care about allocated size.
virtual void *allocate(size_t size, unsigned align = DEFAULT_ALIGN) = 0;
// Frees the memory pointed to by p, the memory must have been allocated by the allocate()
// function. Returns the size of the allocated memomry.
virtual size_t deallocate(void *p) = 0;
};
// Allocator class that wraps the AllocatorApi exposed by the engine's plugin interface.
class ApiAllocator : public Allocator
{
AllocatorObject *_object;
AllocatorApi *_api;
public:
ApiAllocator(AllocatorApi *api, AllocatorObject *object) : _object(object), _api(api) {}
ApiAllocator(const ApiAllocator &a) : Allocator(), _object(a._object), _api(a._api) {}
ApiAllocator & operator=(const ApiAllocator &a) { _object = a._object; _api = a._api; return *this; }
virtual void *allocate(size_t size, unsigned align = DEFAULT_ALIGN) override {return _api->allocate(_object, size, align);}
virtual size_t deallocate(void *p) override {return _api->deallocate(_object, p);}
AllocatorObject *object() { return _object; }
AllocatorApi *api() { return _api; }
};
template <class T> void make_delete(Allocator &a, T *p) {
if (p) {
p->~T();
a.deallocate(p);
}
}
// Allocator that allocates from a static buffer.
class StaticAllocator : public Allocator
{
char *_start;
char *_p;
char *_end;
public:
StaticAllocator(char *p, char *end) : _start(p), _p(p), _end(end) {}
virtual void *allocate(size_t size, unsigned align = DEFAULT_ALIGN) override
{
if (size == 0)
return nullptr;
unsigned rem = (_p - (const char *)0) % align;
if (rem)
_p += (align - rem);
char *ret = _p + size > _end ? nullptr : _p;
_p += size;
return ret;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
size_t deallocate(void *p) override { return 0; }
#pragma GCC diagnostic pop
char *start() {return _start;}
bool out_of_memory() {return _p > _end;}
size_t wanted_memory() {return (size_t)(_p - _start);}
};
// Allocations released only by destructor
class TempAllocator : public ApiAllocator
{
public:
TempAllocator(AllocatorApi *api) : ApiAllocator(api, api->make_temp_allocator()) {}
virtual ~TempAllocator() { api()->destroy_temp_allocator(object()); }
};
// Add this in the public section of classes to specify that they want to be initialized with an
// allocator.
#define ALLOCATOR_AWARE typedef int allocator_aware
// Macro versions of make_new and make_delete to avoid template combinatorial explosion and
// make sure errors are reported in the file where the macro is called.
#define MAKE_NEW(a, T, ...) (new ((a).allocate(sizeof(T), alignof(T))) T(__VA_ARGS__))
#define MAKE_DELETE(a, p) (make_delete(a,p))
#define MAKE_DELETE_TYPE(a, T, p) do {if (p) {(p)->~T(); (a).deallocate(p);}} while (0)
} // namespace stingray_plugin_foundation