56template <
typename Tp,
bool MMapV,
size_t BuffCntV>
89 const Tp*
address(
const Tp& _r)
const {
return &_r; }
94 return (
static_cast<size_t>(0) -
static_cast<size_t>(1)) /
sizeof(Tp);
104 void construct(Tp*
const _p,
const Tp& _v)
const { ::new((
void*) _p) Tp{ _v }; }
106 void construct(Tp*
const _p, Tp&& _v)
const { ::new((
void*) _p) Tp{ std::move(_v) }; }
108 template <
typename... ArgsT>
111 ::new((
void*) _p) Tp{ std::forward<ArgsT>(
_args)... };
114 void destroy(Tp*
const _p)
const { _p->~Tp(); }
124 throw std::length_error(
125 "ring_buffer_allocator<Tp>::allocate() - Integer overflow.");
129 if(n == 1 && !m_buffer_data->dangles.empty())
131 Tp* _p = m_buffer_data->dangles.back();
132 m_buffer_data->dangles.pop_back();
142 if(n > m_buffer_data->current->free())
144 m_buffer_data->dangles.reserve(m_buffer_data->dangles.size() +
145 m_buffer_data->current->free());
146 for(
size_t i = 0; i < m_buffer_data->current->free(); ++i)
148 auto _req = m_buffer_data->current->request();
151 m_buffer_data->dangles.emplace_back(_req);
154 m_buffer_data->current =
nullptr;
160 auto* _p = m_buffer_data->current->request();
163 for(
size_t i = 1; i < n; ++i)
164 m_buffer_data->current->request();
173 m_buffer_data->dangles.reserve(m_buffer_data->dangles.size() + n);
175 for(
size_t i = 0; i < n; ++i)
178 m_buffer_data->dangles.emplace_back(_p);
182 Tp*
allocate(
const size_t n,
const void*
const )
const
187 void reserve(
const size_t n) { init_current(n); }
191 template <
typename FuncT>
194 if(BuffCntV > 0 || get_config_data().initialized)
195 throw std::runtime_error(
"Error! Buffer size has already been fixed");
196 get_config_data().buffer_count_cb = std::forward<FuncT>(_f);
209 m_buffer_data->buffers.reserve(m_buffer_data->buffers.size() +
210 rhs.m_buffer_this.buffers.size());
211 m_buffer_data->dangles.reserve(m_buffer_data->dangles.size() +
212 rhs.m_buffer_this.dangles.size());
213 for(
auto& itr : rhs.m_buffer_this.buffers)
214 m_buffer_data->buffers.emplace_back(std::move(itr));
215 for(
auto& itr : rhs.m_buffer_this.dangles)
216 m_buffer_data->dangles.emplace_back(itr);
217 if(m_buffer_data->current ==
nullptr)
218 m_buffer_data->current = rhs.m_buffer_this.current;
219 rhs.m_buffer_data = m_buffer_data;
222#if !defined(TIMEMORY_INTERNAL_TESTING)
228 bool initialized =
false;
229 size_t buffer_count = 0;
230 std::function<size_t()> buffer_count_cb = []() {
231 return get_env<size_t>(
"TIMEMORY_RING_BUFFER_ALLOCATOR_BUFFER_COUNT",
232 units::get_page_size() /
sizeof(Tp));
238 return (BuffCntV > 0) ? BuffCntV : buffer_count_cb();
245 std::vector<std::unique_ptr<buffer_type>> buffers = {};
246 std::vector<Tp*> dangles = {};
249 static config_data& get_config_data()
251 static config_data _v{};
255 static size_t get_buffer_count()
258 static auto _v = get_config_data().get();
262 buffer_data* get_buffer_data()
const {
return m_buffer_data; }
265 void init_current(
size_t n)
const
267 if(m_buffer_data->current ==
nullptr || m_buffer_data->current->is_full())
269 auto _n = std::max<size_t>(n, get_buffer_count());
270 auto _uniq = std::make_unique<buffer_type>(_n, MMapV);
271 m_buffer_data->buffers.emplace_back(std::move(_uniq));
272 m_buffer_data->current = m_buffer_data->buffers.back().get();
276 mutable buffer_data m_buffer_this{};
277 mutable buffer_data* m_buffer_data = &m_buffer_this;
allocator that uses array of (ring) buffers to coalesce memory. Requires This allocator propagates on...
void construct(Tp *const _p, ArgsT &&... _args) const
void construct(Tp *const _p, Tp &&_v) const
ring_buffer_allocator(ring_buffer_allocator &&) noexcept=default
ring_buffer_allocator(const ring_buffer_allocator &)=default
std::allocator< Tp > base_type
data_storage::ring_buffer< Tp > buffer_type
void construct(Tp *const _p, const Tp &_v) const
void reserve(const size_t n)
Tp * allocate(const size_t n) const
std::true_type propagate_on_container_swap
bool operator!=(const ring_buffer_allocator &rhs) const
const Tp & const_reference
void deallocate(Tp *const ptr, const size_t n) const
Tp * address(Tp &_r) const
~ring_buffer_allocator()=default
void destroy(Tp *const _p) const
static void set_buffer_count_cb(FuncT &&_f)
define a callback function for initializing the buffer size. Will throw if a request for the buffer s...
ring_buffer_allocator()=default
std::true_type propagate_on_container_move_assignment
Tp * allocate(const size_t n, const void *const) const
static void set_buffer_count(size_t _buff_sz)
set the minimum number of objects for the ring buffer. Will throw if a request for the buffer size ha...
const Tp * address(const Tp &_r) const
ptrdiff_t difference_type
void steal_resources(ring_buffer_allocator &rhs)
transfers the buffers to another allocator
std::array< char *, 4 > _args
auto get(const auto_bundle< Tag, Types... > &_obj)
Ring buffer wrapper around tim::base::ring_buffer for data of type Tp. If the data object size is lar...