MCPcopy Create free account
hub / github.com/cameron314/concurrentqueue / enqueue

Method enqueue

concurrentqueue.h:1871–1967  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1869
1870 template<AllocationMode allocMode, typename U>
1871 inline bool enqueue(U&& element)
1872 {
1873 index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);
1874 index_t newTailIndex = 1 + currentTailIndex;
1875 if ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {
1876 // We reached the end of a block, start a new one
1877 auto startBlock = this->tailBlock;
1878 auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;
1879 if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {
1880 // We can re-use the block ahead of us, it's empty!
1881 this->tailBlock = this->tailBlock->next;
1882 this->tailBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();
1883
1884 // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the
1885 // last block from it first -- except instead of removing then adding, we can just overwrite).
1886 // Note that there must be a valid block index here, since even if allocation failed in the ctor,
1887 // it would have been re-attempted when adding the first block to the queue; since there is such
1888 // a block, a block index must have been successfully allocated.
1889 }
1890 else {
1891 // Whatever head value we see here is >= the last value we saw here (relatively),
1892 // and <= its current value. Since we have the most recent tail, the head must be
1893 // <= to it.
1894 auto head = this->headIndex.load(std::memory_order_relaxed);
1895 assert(!details::circular_less_than<index_t>(currentTailIndex, head));
1896 if (!details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE)
1897 || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {
1898 // We can't enqueue in another block because there's not enough leeway -- the
1899 // tail could surpass the head by the time the block fills up! (Or we'll exceed
1900 // the size limit, if the second part of the condition was true.)
1901 return false;
1902 }
1903 // We're going to need a new block; check that the block index has room
1904 if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) {
1905 // Hmm, the circular block index is already full -- we'll need
1906 // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if
1907 // the initial allocation failed in the constructor.
1908
1909 MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {
1910 return false;
1911 }
1912 else if (!new_block_index(pr_blockIndexSlotsUsed)) {
1913 return false;
1914 }
1915 }
1916
1917 // Insert a new block in the circular linked list
1918 auto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();
1919 if (newBlock == nullptr) {
1920 return false;
1921 }
1922#ifdef MCDBGQ_TRACKMEM
1923 newBlock->owner = this;
1924#endif
1925 newBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();
1926 if (this->tailBlock == nullptr) {
1927 newBlock->next = newBlock;
1928 }

Callers

nothing calls this directly

Calls 5

assertClass · 0.85
MOODYCAMEL_CONSTEXPR_IFFunction · 0.85
new_block_indexFunction · 0.85
loadMethod · 0.45
storeMethod · 0.45

Tested by

no test coverage detected