Flow
Documentation for the Flow C++ Library
Loading...
Searching...
No Matches
flow_memory_algorithm.h
Go to the documentation of this file.
1#pragma once
2#include <cassert>
3#include <iterator>
4#include <memory>
5
6namespace flow {
7
14 template <typename AllocatorType, std::input_iterator InputIt, std::forward_iterator OutputIt>
15 OutputIt uninitializedForward(AllocatorType& allocator, InputIt first, InputIt last, OutputIt dest) {
16 for (; first != last; ++first, ++dest) {
17 std::allocator_traits<AllocatorType>::construct(allocator, std::addressof(*dest), *first);
18 }
19 return dest;
20 }
21
28 template <typename AllocatorType, std::input_iterator InputIt, std::forward_iterator OutputIt>
29 OutputIt uninitializedMove(AllocatorType& allocator, InputIt first, InputIt last, OutputIt dest) noexcept {
30 return uninitializedForward(allocator, std::move_iterator(first), std::move_iterator(last), dest);
31 }
32
40 template <typename AllocatorType, std::forward_iterator OutputIt, typename ...Args>
41 OutputIt uninitializedEmplace(AllocatorType& allocator, OutputIt first, OutputIt last, const Args&... args) {
42 for (; first != last; ++first) {
43 std::allocator_traits<AllocatorType>::construct(allocator, std::addressof(*first), args...);
44 }
45 return first;
46 }
47
54 template <typename AllocatorType, std::forward_iterator OutputIt, typename T>
55 OutputIt uninitializedFill(AllocatorType& allocator, OutputIt first, OutputIt last, const T& value) {
56 return uninitializedEmplace(allocator, first, last, value);
57 }
58
63 template <typename AllocatorType, std::forward_iterator InputIt>
64 void destroyElements(AllocatorType& allocator, InputIt first, InputIt last) noexcept {
65 for (; first != last; ++first) {
66 std::allocator_traits<AllocatorType>::destroy(allocator, std::addressof(*first));
67 }
68 }
69
76 template <typename AllocatorType, std::input_iterator InputIt, std::forward_iterator OutputIt>
77 OutputIt uninitializedForwardN(AllocatorType& allocator, InputIt first, std::size_t count, OutputIt dest) {
78 for (std::size_t i = 0; i < count; ++i, ++first, ++dest) {
79 std::allocator_traits<AllocatorType>::construct(allocator, std::addressof(*dest), *first);
80 }
81 return dest;
82 }
83
90 template <typename AllocatorType, std::input_iterator InputIt, std::forward_iterator OutputIt>
91 OutputIt uninitializedMoveN(AllocatorType& allocator, InputIt first, std::size_t count, OutputIt dest) noexcept {
92 return uninitializedForwardN(allocator, std::move_iterator(first), count, dest);
93 }
94
102 template <typename AllocatorType, std::forward_iterator OutputIt, typename ...Args>
103 OutputIt uninitializedEmplaceN(AllocatorType& allocator, OutputIt first, std::size_t count, const Args&... args) {
104 for (std::size_t i = 0; i < count; ++i, ++first) {
105 std::allocator_traits<AllocatorType>::construct(allocator, std::addressof(*first), args...);
106 }
107 return first;
108 }
109
116 template <typename AllocatorType, std::forward_iterator OutputIt, typename T>
117 OutputIt uninitializedFillN(AllocatorType& allocator, OutputIt first, std::size_t count, const T& value) {
118 return uninitializedEmplaceN(allocator, first, count, value);
119 }
120
125 template <typename AllocatorType, std::forward_iterator InputIt>
126 void destroyElementsN(AllocatorType& allocator, InputIt first, std::size_t count) noexcept {
127 for (std::size_t i = 0; i < count; ++i, ++first) {
128 std::allocator_traits<AllocatorType>::destroy(allocator, std::addressof(*first));
129 }
130 }
131
137 template <typename AllocatorType, typename T>
138 void deleteBuffer(AllocatorType& allocator, T* buffer, std::size_t size, std::size_t capacity) noexcept {
139 destroyElementsN(allocator, buffer, size);
140 std::allocator_traits<AllocatorType>::deallocate(allocator, buffer, capacity);
141 }
142
147 template <typename T, typename U>
148 std::size_t pointerDistance(const T* first, const U* last) {
149 assert(first <= last && "first pointer address must be smaller than the last pointer address");
150 return reinterpret_cast<const std::byte*>(last) - reinterpret_cast<const std::byte*>(first);
151 }
152
160 template <typename Header>
161 Header* alignWithHeader(std::size_t alignment, std::size_t size, void*& buffer, std::size_t& capacity) noexcept {
162
163 // https://stackoverflow.com/questions/46457449/is-it-always-the-case-that-sizeoft-alignoft-for-all-object-types-t
164 assert(size >= alignment && "size is smaller than its alignment");
165 if (capacity < sizeof(Header) + size) {
166 return nullptr;
167 }
168
169 // Set the block alignment to be at least as big as the header alignment.
170 alignment = std::max(alignment, alignof(Header));
171
172 // Reserve at least sizeof(Header) before the allocated block.
173 void* allocatedBlock = reinterpret_cast<Header*>(buffer) + 1;
174 std::size_t capacityAfterHeader = capacity - sizeof(Header);
175 if (!std::align(alignment, size, allocatedBlock, capacityAfterHeader)) {
176 return nullptr;
177 }
178
179 // Calculate the address of the header.
180 Header* header = reinterpret_cast<Header*>(allocatedBlock) - 1;
181 assert(reinterpret_cast<std::uintptr_t>(header) % alignof(Header) == 0 && "allocated buffer is not aligned with the header");
182
183 capacity -= pointerDistance(buffer, header);
184 buffer = header;
185 return header;
186 }
187
188}
OutputIt uninitializedEmplace(AllocatorType &allocator, OutputIt first, OutputIt last, const Args &... args)
Constructs objects in uninitialized memory by copying arguments to their constructor....
void destroyElements(AllocatorType &allocator, InputIt first, InputIt last) noexcept
Destroys a range of constructed objects in memory.
OutputIt uninitializedMoveN(AllocatorType &allocator, InputIt first, std::size_t count, OutputIt dest) noexcept
Moves count elements from a source range to uninitialized memory.
void destroyElementsN(AllocatorType &allocator, InputIt first, std::size_t count) noexcept
Destroys count objects in a range.
std::size_t pointerDistance(const T *first, const U *last)
Calculate the distance in bytes from the first pointer to the last pointer.
OutputIt uninitializedMove(AllocatorType &allocator, InputIt first, InputIt last, OutputIt dest) noexcept
Moves elements from a source range to uninitialized memory.
OutputIt uninitializedFillN(AllocatorType &allocator, OutputIt first, std::size_t count, const T &value)
Fills count elements in uninitialized memory with a value.
OutputIt uninitializedForwardN(AllocatorType &allocator, InputIt first, std::size_t count, OutputIt dest)
Forward count elements from a source range to uninitialized memory.
OutputIt uninitializedForward(AllocatorType &allocator, InputIt first, InputIt last, OutputIt dest)
Forward elements from a source range to uninitialized memory.
void deleteBuffer(AllocatorType &allocator, T *buffer, std::size_t size, std::size_t capacity) noexcept
Destroys and deallocates the buffer.
OutputIt uninitializedFill(AllocatorType &allocator, OutputIt first, OutputIt last, const T &value)
Fills uninitialized memory with copies of a value.
Header * alignWithHeader(std::size_t alignment, std::size_t size, void *&buffer, std::size_t &capacity) noexcept
Align the header + buffer to their corresponding alignments. If the capacity is not big enough,...
OutputIt uninitializedEmplaceN(AllocatorType &allocator, OutputIt first, std::size_t count, const Args &... args)
Constructs a specified number of objects in uninitialized memory by copying constructor arguments....