Skip to content

Commit bbc0884

Browse files
committed
Refactor push logic in LockFreeSpscQueue
Simplified the try_push and emplace logic by introducing a get_next_slot() helper to select the correct memory slot. This reduces code duplication and ensures consistent object construction and destruction in the queue.
1 parent 5667a9b commit bbc0884

1 file changed

Lines changed: 25 additions & 15 deletions

File tree

include/LockFreeSpscQueue.h

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -391,27 +391,27 @@ class LockFreeSpscQueue
391391
*/
392392
bool try_push(const T& item)
393393
{
394-
if (m_items_pushed_count >= m_total_reserved_size) return false;
395-
396-
if (m_items_pushed_count < m_block1.size()) {
397-
m_block1[m_items_pushed_count] = item;
398-
} else {
399-
m_block2[m_items_pushed_count - m_block1.size()] = item;
394+
if (m_items_pushed_count >= m_total_reserved_size) {
395+
return false;
400396
}
397+
398+
// Construct a new object in its place by copying.
399+
*get_next_slot() = item;
400+
401401
m_items_pushed_count++;
402402
return true;
403403
}
404404

405405
// Overload for movable types
406406
bool try_push(T&& item)
407407
{
408-
if (m_items_pushed_count >= m_total_reserved_size) return false;
409-
410-
if (m_items_pushed_count < m_block1.size()) {
411-
m_block1[m_items_pushed_count] = std::move(item);
412-
} else {
413-
m_block2[m_items_pushed_count - m_block1.size()] = std::move(item);
408+
if (m_items_pushed_count >= m_total_reserved_size) {
409+
return false;
414410
}
411+
412+
// Construct a new object in its place by moving.
413+
*get_next_slot() = std::move(item);
414+
415415
m_items_pushed_count++;
416416
return true;
417417
}
@@ -433,9 +433,12 @@ class LockFreeSpscQueue
433433
return false;
434434
}
435435

436-
T* slot_ptr = (m_items_pushed_count < m_block1.size())
437-
? &m_block1[m_items_pushed_count]
438-
: &m_block2[m_items_pushed_count - m_block1.size()];
436+
T* slot_ptr = get_next_slot();
437+
438+
// First, destroy the (potentially moved-from) object in the slot.
439+
if constexpr (!std::is_trivially_destructible_v<T>) {
440+
std::destroy_at(slot_ptr);
441+
}
439442

440443
// Construct the object directly in the queue's memory buffer.
441444
std::construct_at(slot_ptr, std::forward<Args>(args)...);
@@ -453,6 +456,7 @@ class LockFreeSpscQueue
453456
{
454457
if (m_owner_queue != nullptr) {
455458
m_owner_queue->commit_write(m_items_pushed_count);
459+
m_owner_queue = nullptr;
456460
}
457461
}
458462

@@ -476,6 +480,12 @@ class LockFreeSpscQueue
476480
, m_block1(b1), m_block2(b2)
477481
, m_total_reserved_size(b1.size() + b2.size()) {}
478482

483+
T* get_next_slot() {
484+
return (m_items_pushed_count < m_block1.size())
485+
? &m_block1[m_items_pushed_count]
486+
: &m_block2[m_items_pushed_count - m_block1.size()];
487+
}
488+
479489
LockFreeSpscQueue* m_owner_queue = nullptr;
480490
std::span<T> m_block1;
481491
std::span<T> m_block2;

0 commit comments

Comments
 (0)