#pragma once namespace detail::refcount_hive { // The element as allocated in memory needs to be at-least 2*skipfield_type width in order to support free list indexes in // erased element memory space, so: make the size of this struct the larger of alignof(T), sizeof(T) or 2*skipfield_type // (the latter is only relevant for type char/uchar), and make the alignment alignof(T). This type is used mainly for // correct pointer arithmetic while iterating over elements in memory. template struct alignas(alignof(element_type)) aligned_element_struct { // Using char as sizeof is always guaranteed to be 1 byte regardless of the number of bits in a byte on given computer, // whereas for example, uint8_t would fail on machines where there are more than 8 bits in a byte eg. Texas Instruments // C54x DSPs. char data[(sizeof(element_type) < (sizeof(skipfield_type) * 2)) ? ((sizeof(skipfield_type) * 2) < alignof(element_type) ? alignof(element_type) : (sizeof(skipfield_type) * 2)) : ((sizeof(element_type) < alignof(element_type)) ? alignof(element_type) : sizeof(element_type))]; }; // We combine the allocation of elements and skipfield into one allocation to save performance. This memory must be // allocated as an aligned type with the same alignment as T in order for the elements to align with memory boundaries // correctly (which won't happen if we allocate as char or uint_8). But the larger the sizeof in the type we use for // allocation, the greater the chance of creating a lot of unused memory in the skipfield portion of the allocated block. So // we create a type that is sizeof(alignof(T)), as in most cases alignof(T) < sizeof(T). If alignof(t) >= sizeof(t) this // makes no difference. template struct alignas(alignof(element_type)) aligned_allocation_struct { char data[alignof(element_type)]; }; // Calculate the capacity of a group's elements+skipfield memory block when expressed in multiples of the value_type's // alignment (rounding up). template static size_t get_aligned_block_capacity(const skipfield_type elements_per_group) { using aligned_element_struct = aligned_element_struct; using aligned_allocation_struct = aligned_allocation_struct; return ((elements_per_group * (sizeof(aligned_element_struct) + sizeof(skipfield_type))) + sizeof(skipfield_type) + sizeof(aligned_allocation_struct) - 1) / sizeof(aligned_allocation_struct); } // To enable conversion when allocator supplies non-raw pointers: template static constexpr destination_pointer_type pointer_cast(const source_pointer_type source_pointer) noexcept { return destination_pointer_type(&*source_pointer); } } // namespace detail::refcount_hive