9 #include <density/default_allocator.h> 11 #include <density/runtime_type.h> 13 #include <type_traits> 45 template <
typename UNDERLYING_ALLOCATOR = default_allocator,
size_t ALIGNMENT = alignof(
void *)>
49 static_assert(ALIGNMENT > 0 &&
is_power_of_2(ALIGNMENT),
"ALIGNMENT must be a power of 2");
59 alignment <= UNDERLYING_ALLOCATOR::page_alignment,
60 "The alignment of the pages is too small");
67 : UNDERLYING_ALLOCATOR(i_underlying_allocator)
73 : UNDERLYING_ALLOCATOR(
std::move(i_underlying_allocator))
95 DENSITY_ASSUME_UINT_ALIGNED(i_size, alignment);
97 auto const new_top = m_top + i_size;
98 auto const new_offset =
100 if (!
DENSITY_LIKELY(new_offset < UNDERLYING_ALLOCATOR::page_size))
103 return allocate_slow_path(i_size);
109 auto const new_block =
reinterpret_cast<void *
>(m_top);
143 DENSITY_ASSUME_UINT_ALIGNED(i_size, alignment);
146 if (!
DENSITY_LIKELY(same_page(i_block, reinterpret_cast<void *>(m_top))))
148 deallocate_slow_path(i_block, i_size);
152 m_top =
reinterpret_cast<uintptr_t
>(i_block);
172 void *
reallocate(
void * i_block,
size_t i_old_size,
size_t i_new_size)
175 if (same_page(i_block, reinterpret_cast<void *>(m_top)))
178 auto const new_block = set_top_and_allocate(i_block, i_new_size);
180 copy(i_block, i_old_size, new_block, i_new_size);
186 (m_top & (UNDERLYING_ALLOCATOR::page_alignment - 1)) ==
sizeof(PageHeader) &&
187 same_page(reinterpret_cast<PageHeader *>(m_top)[-1].m_prev_page, i_block))
189 auto const page_to_deallocate =
reinterpret_cast<void *
>(m_top);
193 auto const new_block = set_top_and_allocate(i_block, i_new_size);
195 copy(i_block, i_old_size, new_block, i_new_size);
197 UNDERLYING_ALLOCATOR::deallocate_page(page_to_deallocate);
203 auto const new_block =
allocate(i_new_size);
204 copy(i_block, i_old_size, new_block, i_new_size);
205 UNDERLYING_ALLOCATOR::deallocate(i_block, i_old_size, alignment);
214 if (m_top != s_virgin_top)
216 UNDERLYING_ALLOCATOR::deallocate_page(reinterpret_cast<void *>(m_top));
228 struct alignas(alignment) alignas(void *) PageHeader
234 UNDERLYING_ALLOCATOR::page_size / 2 >
sizeof(PageHeader),
"page_size is too small");
237 static bool same_page(
const void * i_first,
const void * i_second) noexcept
239 auto const page_mask = UNDERLYING_ALLOCATOR::page_alignment - 1;
240 return ((reinterpret_cast<uintptr_t>(i_first) ^ reinterpret_cast<uintptr_t>(i_second)) &
246 DENSITY_ASSUME_UINT_ALIGNED(i_size, alignment);
247 if (i_size < UNDERLYING_ALLOCATOR::page_size / 2)
250 auto const new_page = UNDERLYING_ALLOCATOR::allocate_page();
252 auto const new_header =
new (new_page) PageHeader;
253 new_header->m_prev_page =
reinterpret_cast<void *
>(m_top);
254 m_top =
reinterpret_cast<uintptr_t
>(new_header + 1) + i_size;
255 return new_header + 1;
260 return UNDERLYING_ALLOCATOR::allocate(i_size, alignment);
264 DENSITY_NO_INLINE void deallocate_slow_path(
void * i_block,
size_t i_size) noexcept
266 DENSITY_ASSUME_UINT_ALIGNED(i_size, alignment);
269 (m_top & (UNDERLYING_ALLOCATOR::page_alignment - 1)) ==
sizeof(PageHeader) &&
270 same_page(reinterpret_cast<PageHeader *>(m_top)[-1].m_prev_page, i_block))
273 auto const page_to_deallocate =
reinterpret_cast<void *
>(m_top);
275 UNDERLYING_ALLOCATOR::deallocate_page(page_to_deallocate);
276 m_top =
reinterpret_cast<uintptr_t
>(i_block);
281 UNDERLYING_ALLOCATOR::deallocate(i_block, i_size, alignment);
287 void * set_top_and_allocate(
void *
const i_current_top,
size_t const i_size)
289 DENSITY_ASSUME_UINT_ALIGNED(i_size, alignment);
291 auto const current_top =
reinterpret_cast<uintptr_t
>(i_current_top);
294 auto const new_top = current_top + i_size;
295 auto const new_offset =
296 new_top -
uint_lower_align(current_top, UNDERLYING_ALLOCATOR::page_alignment);
297 if (new_offset < UNDERLYING_ALLOCATOR::page_size)
300 auto const new_block = i_current_top;
304 else if (i_size < UNDERLYING_ALLOCATOR::page_size / 2)
307 auto const new_page =
308 static_cast<PageHeader *
>(UNDERLYING_ALLOCATOR::allocate_page());
309 new_page->m_prev_page =
reinterpret_cast<void *
>(current_top);
310 m_top =
reinterpret_cast<uintptr_t
>(new_page + 1) + i_size;
316 auto const new_external_block = UNDERLYING_ALLOCATOR::allocate(i_size, alignment);
317 m_top =
reinterpret_cast<uintptr_t
>(i_current_top);
318 return new_external_block;
323 void * i_old_block,
size_t i_old_size,
void * i_new_block,
size_t i_new_size) noexcept
325 if (i_old_block != i_new_block)
327 auto const size_to_copy = detail::size_min(i_new_size, i_old_size);
328 DENSITY_ASSUME_UINT_ALIGNED(size_to_copy, alignment);
331 memcpy(i_new_block, i_old_block, size_to_copy);
336 static constexpr uintptr_t s_virgin_top =
338 uintptr_t m_top = s_virgin_top;
346 template <
int = 0>
class ThreadLifoAllocator
348 #ifndef DENSITY_USER_DATA_STACK 356 static void *
allocate(
size_t i_size) {
return s_allocator.allocate(i_size); }
358 static void *
allocate_empty() noexcept {
return s_allocator.allocate_empty(); }
360 static void *
reallocate(
void * i_block,
size_t i_old_size,
size_t i_new_size)
362 return s_allocator.reallocate(i_block, i_old_size, i_new_size);
365 static void deallocate(
void * i_block,
size_t i_size) noexcept
367 s_allocator.deallocate(i_block, i_size);
377 static constexpr
size_t alignment = user_data_stack::alignment;
379 static void *
allocate(
size_t i_size) {
return user_data_stack::allocate(i_size); }
381 static void *
allocate_empty() noexcept {
return user_data_stack::allocate_empty(); }
383 static void *
reallocate(
void * i_block,
size_t i_old_size,
size_t i_new_size)
385 return user_data_stack::reallocate(i_block, i_old_size, i_new_size);
388 static void deallocate(
void * i_block,
size_t i_size) noexcept
390 user_data_stack::deallocate(i_block, i_size);
396 #ifndef DENSITY_USER_DATA_STACK 399 ThreadLifoAllocator<DUMMY>::s_allocator;
425 static constexpr
size_t alignment = detail::ThreadLifoAllocator<>::alignment;
449 detail::ThreadLifoAllocator<>::deallocate(m_data,
uint_upper_align(m_size, alignment));
467 auto const block = m_data = detail::ThreadLifoAllocator<>::reallocate(
475 void *
data() const noexcept {
return m_data; }
478 size_t size() const noexcept {
return m_size; }
489 bool OVER_ALIGNED = (
alignof(TYPE) > detail::ThreadLifoAllocator<>::alignment)>
492 template <
typename TYPE>
class LifoArrayImpl<TYPE, false>
495 static size_t compute_mem_size(
size_t i_element_count) noexcept
497 auto const mem_size = i_element_count *
sizeof(TYPE);
498 bool already_aligned =
sizeof(TYPE) % detail::ThreadLifoAllocator<>::alignment == 0;
502 return uint_upper_align(mem_size, detail::ThreadLifoAllocator<>::alignment);
505 LifoArrayImpl(
size_t i_element_count)
506 : m_elements(static_cast<TYPE *>(
507 detail::ThreadLifoAllocator<>::allocate(compute_mem_size(i_element_count)))),
508 m_size(i_element_count)
514 detail::ThreadLifoAllocator<>::deallocate(m_elements, compute_mem_size(m_size));
518 TYPE *
const m_elements;
522 template <
typename TYPE>
class LifoArrayImpl<TYPE, true>
525 static constexpr
size_t size_overhead =
526 alignof(TYPE) - detail::ThreadLifoAllocator<>::alignment;
528 static size_t compute_mem_size(
size_t i_element_count) noexcept
530 auto const mem_size = i_element_count *
sizeof(TYPE) + size_overhead;
531 bool already_aligned =
sizeof(TYPE) % detail::ThreadLifoAllocator<>::alignment == 0;
535 return uint_upper_align(mem_size, detail::ThreadLifoAllocator<>::alignment);
538 LifoArrayImpl(
size_t i_size) : m_size(i_size)
540 auto const mem_size = compute_mem_size(m_size);
541 m_block = detail::ThreadLifoAllocator<>::allocate(mem_size);
545 m_elements + m_size <=
address_add(m_block, mem_size));
550 auto const mem_size = compute_mem_size(m_size);
551 detail::ThreadLifoAllocator<>::deallocate(m_block, mem_size);
583 template <
typename TYPE>
class lifo_array final : detail::LifoArrayImpl<TYPE>
590 using value_type = TYPE;
591 using reference = TYPE &;
592 using const_reference = TYPE &;
593 using pointer = TYPE *;
594 using const_pointer =
const TYPE *;
595 using size_type = size_t;
596 using difference_type = ptrdiff_t;
601 using difference_type = ptrdiff_t;
602 using value_type = TYPE;
603 using pointer = TYPE *;
604 using reference = TYPE &;
605 using iterator_category = std::random_access_iterator_tag;
607 iterator(PrivateTag, TYPE * i_ptr) noexcept : m_curr(i_ptr) {}
609 iterator() noexcept =
default;
610 iterator(
const iterator &) noexcept =
default;
611 iterator &
operator=(
const iterator &) noexcept =
default;
613 TYPE * operator->()
const noexcept {
return m_curr; }
615 TYPE & operator*()
const & noexcept {
return *m_curr; }
617 TYPE && operator*()
const && noexcept {
return *m_curr; }
619 iterator & operator++() noexcept
625 iterator operator++(
int) noexcept
627 iterator copy(*
this);
632 iterator & operator+=(difference_type i_diff) noexcept
638 iterator & operator--() noexcept
644 iterator operator--(
int) noexcept
646 iterator copy(*
this);
651 iterator & operator-=(difference_type i_diff) noexcept
657 friend difference_type
658 operator-(
const iterator & i_first,
const iterator & i_second) noexcept
660 return i_first.m_curr - i_second.m_curr;
665 friend bool operator<(
const iterator & i_first,
const iterator & i_second) noexcept
667 return i_first.m_curr < i_second.m_curr;
670 friend bool operator<=(
const iterator & i_first,
const iterator & i_second) noexcept
672 return i_first.m_curr <= i_second.m_curr;
675 friend bool operator==(
const iterator & i_first,
const iterator & i_second) noexcept
677 return i_first.m_curr == i_second.m_curr;
680 friend bool operator!=(
const iterator & i_first,
const iterator & i_second) noexcept
682 return i_first.m_curr != i_second.m_curr;
685 friend bool operator>(
const iterator & i_first,
const iterator & i_second) noexcept
687 return i_first.m_curr > i_second.m_curr;
690 friend bool operator>=(
const iterator & i_first,
const iterator & i_second) noexcept
692 return i_first.m_curr >= i_second.m_curr;
702 using difference_type = ptrdiff_t;
703 using value_type =
const TYPE;
704 using pointer =
const TYPE *;
705 using reference =
const TYPE &;
706 using iterator_category = std::random_access_iterator_tag;
708 const_iterator(PrivateTag,
const TYPE * i_ptr) noexcept : m_curr(i_ptr) {}
710 const_iterator() noexcept =
default;
711 const_iterator(
const const_iterator &) noexcept =
default;
712 const_iterator &
operator=(
const const_iterator &) noexcept =
default;
714 const TYPE * operator->()
const noexcept {
return m_curr; }
716 const TYPE & operator*()
const & noexcept {
return *m_curr; }
718 const TYPE && operator*()
const && noexcept {
return *m_curr; }
720 const_iterator & operator++() noexcept
726 const_iterator operator++(
int) noexcept
728 const_iterator copy(*
this);
733 const_iterator & operator+=(difference_type i_diff) noexcept
739 const_iterator & operator--() noexcept
745 const_iterator operator--(
int) noexcept
747 const_iterator copy(*
this);
752 const_iterator & operator-=(difference_type i_diff) noexcept
758 friend difference_type
759 operator-(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
761 return i_first.m_curr - i_second.m_curr;
767 operator<(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
769 return i_first.m_curr < i_second.m_curr;
773 operator<=(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
775 return i_first.m_curr <= i_second.m_curr;
779 operator==(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
781 return i_first.m_curr == i_second.m_curr;
785 operator!=(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
787 return i_first.m_curr != i_second.m_curr;
791 operator>(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
793 return i_first.m_curr > i_second.m_curr;
797 operator>=(
const const_iterator & i_first,
const const_iterator & i_second) noexcept
799 return i_first.m_curr >= i_second.m_curr;
803 const TYPE * m_curr{};
808 lifo_array(
size_t i_size) : detail::LifoArrayImpl<TYPE>(i_size)
810 default_construct(std::is_pod<TYPE>());
818 template <
typename... CONSTRUCTION_PARAMS>
819 lifo_array(
size_t i_size,
const CONSTRUCTION_PARAMS &... i_construction_params)
820 : detail::LifoArrayImpl<TYPE>(i_size)
822 size_t element_index = 0;
825 for (; element_index < i_size; element_index++)
827 new (m_elements + element_index) TYPE(i_construction_params...);
833 auto it = m_elements + element_index;
835 for (; it >= m_elements; it--)
848 template <
typename INPUT_ITERATOR>
850 INPUT_ITERATOR i_begin,
851 INPUT_ITERATOR i_end,
852 typename std::iterator_traits<INPUT_ITERATOR>::iterator_category =
853 typename std::iterator_traits<INPUT_ITERATOR>::iterator_category())
854 : detail::LifoArrayImpl<TYPE>(
std::distance(i_begin, i_end))
856 auto dest_element = m_elements;
859 for (; i_begin != i_end; ++i_begin)
862 new (dest_element) TYPE(*i_begin);
869 auto count_to_destroy = dest_element - m_elements;
870 while (count_to_destroy > 0)
874 dest_element->TYPE::~TYPE();
887 ~lifo_array() { destroy_elements(std::is_trivially_destructible<TYPE>()); }
890 size_t size() const noexcept {
return m_size; }
900 return m_elements[i_index];
911 return m_elements[i_index];
915 pointer
data() noexcept {
return m_elements; }
918 const_pointer
data() const noexcept {
return m_elements; }
920 iterator begin() noexcept {
return iterator(PrivateTag{}, m_elements); }
922 iterator end() noexcept {
return iterator(PrivateTag{}, m_elements + m_size); }
924 const_iterator cbegin()
const noexcept {
return const_iterator(PrivateTag{}, m_elements); }
926 const_iterator cend()
const noexcept
928 return const_iterator(PrivateTag{}, m_elements + m_size);
931 const_iterator begin()
const noexcept {
return const_iterator(PrivateTag{}, m_elements); }
933 const_iterator end()
const noexcept
935 return const_iterator(PrivateTag{}, m_elements + m_size);
940 void default_construct(std::true_type) {}
943 void default_construct(std::false_type)
945 size_t element_index = 0;
948 for (; element_index < m_size; element_index++)
950 auto const dest = m_elements + element_index;
958 auto count_to_destroy = element_index;
959 while (count_to_destroy > 0)
962 m_elements[count_to_destroy].TYPE::~TYPE();
968 void destroy_elements(std::true_type) noexcept {}
970 void destroy_elements(std::false_type) noexcept
972 auto it = m_elements + m_size;
974 for (; it >= m_elements; it--)
981 using detail::LifoArrayImpl<TYPE>::m_elements;
982 using detail::LifoArrayImpl<TYPE>::m_size;
void * address_add(void *i_address, size_t i_offset) noexcept
Definition: density_common.h:142
lifo_allocator & operator=(const lifo_allocator &)=delete
Definition: conc_function_queue.h:11
void * reallocate(void *i_block, size_t i_old_size, size_t i_new_size)
Definition: lifo.h:172
~lifo_allocator()
Definition: lifo.h:212
void * allocate(size_t i_size)
Definition: lifo.h:93
Definition: runtime_type.h:1061
lifo_allocator(UNDERLYING_ALLOCATOR &&i_underlying_allocator)
Definition: lifo.h:72
lifo_array(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end, typename std::iterator_traits< INPUT_ITERATOR >::iterator_category=typename std::iterator_traits< INPUT_ITERATOR >::iterator_category())
Definition: lifo.h:849
lifo_array(size_t i_size, const CONSTRUCTION_PARAMS &...i_construction_params)
Definition: lifo.h:819
uintptr_t address_diff(const void *i_end_address, const void *i_start_address) noexcept
Definition: density_common.h:184
const UNDERLYING_ALLOCATOR & underlying_allocator_ref() const noexcept
Definition: lifo.h:224
lifo_buffer(size_t i_size)
Definition: lifo.h:434
#define DENSITY_NO_INLINE
Definition: density_config.h:86
void * data() const noexcept
Definition: lifo.h:475
#define DENSITY_ASSUME_ALIGNED(address, constexpr_alignment)
Definition: density_config.h:59
lifo_allocator(const UNDERLYING_ALLOCATOR &i_underlying_allocator)
Definition: lifo.h:66
UNDERLYING_ALLOCATOR & underlying_allocator_ref() noexcept
Definition: lifo.h:221
constexpr UINT uint_lower_align(UINT i_uint, size_t i_alignment) noexcept
Definition: density_common.h:311
Definition: default_allocator.h:149
const_pointer data() const noexcept
Definition: lifo.h:918
~lifo_array()
Definition: lifo.h:887
void * resize(size_t i_new_size)
Definition: lifo.h:464
lifo_array(size_t i_size)
Definition: lifo.h:808
lifo_buffer() noexcept
Definition: lifo.h:428
size_t size() const noexcept
Definition: lifo.h:890
constexpr bool is_power_of_2(size_t i_number) noexcept
Definition: density_common.h:109
void * address_upper_align(void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:264
void * allocate_empty() noexcept
Definition: lifo.h:129
~lifo_buffer()
Definition: lifo.h:447
#define DENSITY_ASSERT_INTERNAL(...)
Definition: density_config.h:28
size_t size() const noexcept
Definition: lifo.h:478
constexpr lifo_allocator() noexcept
Definition: lifo.h:63
const TYPE & operator[](size_t i_index) const noexcept
Definition: lifo.h:908
constexpr UINT uint_upper_align(UINT i_uint, size_t i_alignment) noexcept
Definition: density_common.h:297
pointer data() noexcept
Definition: lifo.h:915
void deallocate(void *i_block, size_t i_size) noexcept
Definition: lifo.h:140
#define DENSITY_LIKELY(bool_expr)
Definition: density_config.h:76
static constexpr size_t alignment
Definition: lifo.h:55
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
TYPE & operator[](size_t i_index) noexcept
Definition: lifo.h:897