#pragma once #include #include #include #include #include #include #include "memory/alloc.hpp" #include "memory/wrapper.hpp" namespace ipc { namespace mem { namespace detail { template constexpr decltype(auto) static_switch(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) { return def(); } template constexpr decltype(auto) static_switch(std::size_t i, std::index_sequence, F&& f, D&& def) { return (i == N) ? f(std::integral_constant{}) : static_switch(i, std::index_sequence{}, f, def); } } // namespace detail class pool_alloc { private: template static auto& fixed() { static synchronized> pool; return pool; } template static decltype(auto) choose(std::size_t size, F&& f) { enum : std::size_t { base_size = sizeof(void*) }; size = ((size - 1) & (~(base_size - 1))) + base_size; return detail::static_switch(size, std::index_sequence< base_size , base_size * 2 , base_size * 3 , base_size * 4 , base_size * 5 , base_size * 6 , base_size * 7 , base_size * 8 , base_size * 9 , base_size * 10, base_size * 11, base_size * 12, base_size * 13, base_size * 14, base_size * 15, base_size * 16 >{}, [&f](auto index) { return f(fixed()); }, [&f] { return f(static_alloc{}); }); } public: pool_alloc() = default; pool_alloc(const pool_alloc&) = default; pool_alloc& operator=(const pool_alloc&) = default; pool_alloc(pool_alloc&&) = default; pool_alloc& operator=(pool_alloc&&) = default; static constexpr std::size_t remain() { return (std::numeric_limits::max)(); } static constexpr void clear() {} static void* alloc(std::size_t size) { return choose(size, [size](auto&& fp) { return fp.alloc(size); }); } static void free(void* p, std::size_t size) { choose(size, [p](auto&& fp) { fp.free(p); }); } }; template using allocator = allocator_wrapper; template using unordered_map = std::unordered_map< Key, T, std::hash, std::equal_to, allocator> >; template using vector = std::vector>; } // namespace mem } // namespace ipc