90 static_assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) &&
"MAX_BLOCK_SIZE must be a power of 2");
91 static_assert(MAX_BLOCK_SIZE >= 2 &&
"MAX_BLOCK_SIZE must be at least 2");
93 Block* firstBlock =
nullptr;
95 largestBlockSize = ceilToPow2(size + 1);
96 if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
102 size_t initialBlockCount = (size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
103 largestBlockSize = MAX_BLOCK_SIZE;
104 Block* lastBlock =
nullptr;
105 for (
size_t i = 0; i != initialBlockCount; ++i) {
106 auto block = make_block(largestBlockSize);
107 if (block ==
nullptr) {
108 throw std::bad_alloc();
110 if (firstBlock ==
nullptr) {
114 lastBlock->next = block;
117 block->next = firstBlock;
121 firstBlock = make_block(largestBlockSize);
122 if (firstBlock ==
nullptr) {
123 throw std::bad_alloc();
125 firstBlock->next = firstBlock;
127 frontBlock = firstBlock;
128 tailBlock = firstBlock;
132 : frontBlock(other.frontBlock),
133 tailBlock(other.tailBlock),
134 largestBlockSize(other.largestBlockSize)
136 other.largestBlockSize = 32;
137 Block* b = other.make_block(other.largestBlockSize);
139 throw std::bad_alloc();
142 other.frontBlock = b;
148 Block* b = frontBlock;
149 frontBlock = other.frontBlock;
150 other.frontBlock = b;
152 tailBlock = other.tailBlock;
154 std::swap(largestBlockSize, other.largestBlockSize);
161 Block* frontBlock_ = frontBlock;
162 Block* block = frontBlock_;
164 Block* nextBlock = block->next;
165 size_t blockFront = block->front;
166 size_t blockTail = block->tail;
168 for (
size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
169 auto element =
reinterpret_cast<T*
>(block->data + i *
sizeof(T));
177 }
while (block != frontBlock_);
186 return inner_enqueue<CannotAlloc>(element);
194 return inner_enqueue<CannotAlloc>(std::forward<T>(element));
198 template<
typename... Args>
201 return inner_enqueue<CannotAlloc>(std::forward<Args>(args)...);
209 return inner_enqueue<CanAlloc>(element);
217 return inner_enqueue<CanAlloc>(std::forward<T>(element));
221 template<
typename... Args>
224 return inner_enqueue<CanAlloc>(std::forward<Args>(args)...);
240 Block* frontBlock_ = frontBlock;
241 size_t blockTail = frontBlock_->localTail;
242 size_t blockFront = frontBlock_->front;
244 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
246 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
247 result = std::move(*element);
250 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
252 frontBlock_->front = blockFront;
254 else if (frontBlock_ != tailBlock) {
255 frontBlock_ = frontBlock;
256 blockTail = frontBlock_->localTail = frontBlock_->tail;
257 blockFront = frontBlock_->front;
260 Block* nextBlock = frontBlock_->next;
261 size_t nextBlockFront = nextBlock->front;
262 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail;
266 assert(nextBlockFront != nextBlockTail);
267 (void) nextBlockTail;
270 frontBlock = frontBlock_ = nextBlock;
272 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
274 result = std::move(*element);
277 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
279 frontBlock_->front = nextBlockFront;
298 Block* frontBlock_ = frontBlock;
299 size_t blockTail = frontBlock_->localTail;
300 size_t blockFront = frontBlock_->front;
302 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
303 return reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
305 else if (frontBlock_ != tailBlock) {
306 frontBlock_ = frontBlock;
307 blockTail = frontBlock_->localTail = frontBlock_->tail;
308 blockFront = frontBlock_->front;
310 Block* nextBlock = frontBlock_->next;
312 size_t nextBlockFront = nextBlock->front;
314 assert(nextBlockFront != nextBlock->tail);
315 return reinterpret_cast<T*
>(nextBlock->data + nextBlockFront *
sizeof(T));
328 Block* frontBlock_ = frontBlock;
329 size_t blockTail = frontBlock_->localTail;
330 size_t blockFront = frontBlock_->front;
332 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
333 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
336 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
338 frontBlock_->front = blockFront;
340 else if (frontBlock_ != tailBlock) {
341 frontBlock_ = frontBlock;
342 blockTail = frontBlock_->localTail = frontBlock_->tail;
343 blockFront = frontBlock_->front;
346 Block* nextBlock = frontBlock_->next;
348 size_t nextBlockFront = nextBlock->front;
349 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail;
351 assert(nextBlockFront != nextBlockTail);
352 (void) nextBlockTail;
354 frontBlock = frontBlock_ = nextBlock;
356 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
359 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
361 frontBlock_->front = nextBlockFront;
380 Block* frontBlock_ = frontBlock;
381 Block* block = frontBlock_;
383 size_t blockFront = block->front;
384 size_t blockTail = block->tail;
385 result += (blockTail - blockFront) & block->sizeMask;
387 }
while (block != frontBlock_);
395 Block* frontBlock_ = frontBlock;
396 Block* block = frontBlock_;
398 result += block->sizeMask;
400 }
while (block != frontBlock_);
406 enum AllocationMode { CanAlloc, CannotAlloc };
408 template<AllocationMode canAlloc,
typename... Args>
409 bool inner_enqueue(Args&&... args)
418 Block* tailBlock_ = tailBlock;
419 size_t blockFront = tailBlock_->localFront;
420 size_t blockTail = tailBlock_->tail;
422 size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
423 if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front)) {
425 char* location = tailBlock_->data + blockTail *
sizeof(T);
426 new (location) T(std::forward<Args>(args)...);
428 tailBlock_->tail = nextBlockTail;
431 if (tailBlock_->next != frontBlock) {
438 Block* tailBlockNext = tailBlock_->next;
439 size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front;
440 nextBlockTail = tailBlockNext->tail;
444 assert(nextBlockFront == nextBlockTail);
445 tailBlockNext->localFront = nextBlockFront;
447 char* location = tailBlockNext->data + nextBlockTail *
sizeof(T);
448 new (location) T(std::forward<Args>(args)...);
450 tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
452 tailBlock = tailBlockNext;
454 else if constexpr (canAlloc == CanAlloc) {
456 auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
457 auto newBlock = make_block(newBlockSize);
458 if (newBlock ==
nullptr) {
462 largestBlockSize = newBlockSize;
464 new (newBlock->data) T(std::forward<Args>(args)...);
465 assert(newBlock->front == 0);
466 newBlock->tail = newBlock->localTail = 1;
468 newBlock->next = tailBlock_->next;
469 tailBlock_->next = newBlock;
471 tailBlock = newBlock;
473 else if constexpr (canAlloc == CannotAlloc) {
478 assert(
false &&
"Should be unreachable code");
492 static constexpr size_t ceilToPow2(
size_t x)
499 for (
size_t i = 1; i <
sizeof(size_t); i <<= 1) {
509 const std::size_t alignment = std::alignment_of<U>::value;
510 return ptr + (alignment - (
reinterpret_cast<std::uintptr_t
>(
ptr) % alignment)) % alignment;
527 const size_t sizeMask;
530 Block(
size_t _size,
char* _data)
531 : front(0UL), localTail(0), tail(0UL), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1)
537 static Block* make_block(
size_t capacity)
540 auto size =
sizeof(
Block);
541 size +=
sizeof(T) * capacity + std::alignment_of<T>::value - 1;
542 auto newBlock =
static_cast<char*
>(std::malloc(size));
543 if (newBlock ==
nullptr) {
547 auto newBlockData = align_for<T>(newBlock +
sizeof(Block));
548 return new (newBlock)
Block(capacity, newBlockData);
554 size_t largestBlockSize;
SLEIPNIR_DLLEXPORT VariableMatrix Block(std::initializer_list< std::initializer_list< VariableMatrix > > list)
Assemble a VariableMatrix from a nested list of blocks.
Definition VariableMatrix.hpp:988
WPI_BASIC_JSON_TPL_DECLARATION void swap(wpi::WPI_BASIC_JSON_TPL &j1, wpi::WPI_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< wpi::WPI_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< wpi::WPI_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.h:5258