Skip to content

Instantly share code, notes, and snippets.

@yuyoyuppe
Last active August 21, 2020 13:14
Show Gist options
  • Save yuyoyuppe/3544624777c0800c5884aa887774edfc to your computer and use it in GitHub Desktop.
Save yuyoyuppe/3544624777c0800c5884aa887774edfc to your computer and use it in GitHub Desktop.
#include <array>
#include <vector>
#include <memory_resource>
#include <iostream>
int main()
{
std::array<char, 24> memory{};
std::pmr::monotonic_buffer_resource arena{data(memory), size(memory), nullptr};
std::pmr::vector<char> v(8, 'A', &arena);
auto print_state = [&]{
std::cout << "memory: ";
for(const char c : memory) std::cout << '\'' << c << "' ";
std::cout << '\n';
std::cout << "vector [" << size(v) << "]: ";
for(const char c : v) std::cout << '\'' << c << "' ";
std::cout << '\n' << '\n';
};
print_state();
v.clear();
print_state();
v.assign(8, 'B');
print_state();
//v.assign(9, 'B'); // will crash, since arena has `nullptr` as an upstream resource, and we don't have space in arena for 9 chars
return 0;
}
#include <array>
#include <memory_resource>
#include <iostream>
// Make sure we don't call global new/delete
void operator delete(void *) { std::cout << "delete called!\n"; }
void * operator new(std::size_t)
{
std::cout << "new called!\n";
return nullptr;
}
void * operator new(std::size_t, std::align_val_t)
{
std::cout << "new called!\n";
return nullptr;
}
template <class... Args>
constexpr bool all_equal(const Args &... args)
{
if constexpr(sizeof...(Args) == 0)
{
return true;
}
else
{
return [](const auto & head, const auto &... rest) { return ((head == rest) && ...); }(args...);
}
}
template <typename Interface, typename... Types>
class polymorphic_arena_holder
{
// TODO: support different alignment type by desc-sorting the objects
static_assert(all_equal(alignof(Types)...), "types must have the same alignment!");
static inline void deleter(Interface * const ptr) noexcept { ptr->~Interface(); }
using object_ptr_t = std::unique_ptr<Interface, decltype(&deleter)>;
static constexpr size_t storage_size = (sizeof(Types) + ...);
std::aligned_storage_t<storage_size, alignof(Interface)> _storage;
std::pmr::monotonic_buffer_resource _arena;
std::array<object_ptr_t, sizeof...(Types)> _objects;
public:
// TODO: support ctor args
polymorphic_arena_holder()
: _arena{&_storage, storage_size, std::pmr::null_memory_resource()}
, _objects{
object_ptr_t{new(_arena.allocate(sizeof(Types), alignof(Types))) Types{}, deleter}...,
}
{
}
const decltype(_objects) & objects() const { return _objects; }
};
struct base
{
virtual void go() = 0;
virtual ~base(){};
};
struct d1 : base
{
virtual void go() override { std::cout << "d1 go!\n"; }
~d1() { std::cout << "d1 destroyed\n"; }
};
struct d2 : base
{
virtual void go() override { std::cout << "d2 go!\n"; }
~d2() { std::cout << "d2 destroyed\n"; }
};
int main()
{
polymorphic_arena_holder<base, d1, d2> holder;
for(auto & b : holder.objects())
b->go();
return 0;
}
@yuyoyuppe
Copy link
Author

yuyoyuppe commented Aug 21, 2020

Output:

example 1:

memory: ' ' '�' '�' '�' '�' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'A' 'A' 'A' 'A' 'A' 'A' 'A' 'A'
vector [8]: 'A' 'A' 'A' 'A' 'A' 'A' 'A' 'A'

memory: ' ' '�' '�' '�' '�' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'A' 'A' 'A' 'A' 'A' 'A' 'A' 'A'
vector [0]:

memory: ' ' '�' '�' '�' '�' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B'
vector [8]: 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B'

example 2:

d1 go!      
d2 go!      
d2 destroyed
d1 destroyed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment