| 2763 | |
| 2764 | template<typename It> |
| 2765 | size_t dequeue_bulk(It &itemFirst, size_t max) { |
| 2766 | auto tail = this->tailIndex.load(std::memory_order_relaxed); |
| 2767 | auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); |
| 2768 | auto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load( |
| 2769 | std::memory_order_relaxed) - overcommit)); |
| 2770 | if (details::circular_less_than<size_t>(0, desiredCount)) { |
| 2771 | desiredCount = desiredCount < max ? desiredCount : max; |
| 2772 | std::atomic_thread_fence(std::memory_order_acquire); |
| 2773 | |
| 2774 | auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, |
| 2775 | std::memory_order_relaxed); |
| 2776 | assert(overcommit <= myDequeueCount); |
| 2777 | |
| 2778 | tail = this->tailIndex.load(std::memory_order_acquire); |
| 2779 | auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit)); |
| 2780 | if (details::circular_less_than<size_t>(0, actualCount)) { |
| 2781 | actualCount = desiredCount < actualCount ? desiredCount : actualCount; |
| 2782 | if (actualCount < desiredCount) { |
| 2783 | this->dequeueOvercommit.fetch_add(desiredCount - actualCount, |
| 2784 | std::memory_order_release); |
| 2785 | } |
| 2786 | |
| 2787 | // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this |
| 2788 | // will never exceed tail. |
| 2789 | auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); |
| 2790 | |
| 2791 | // Iterate the blocks and dequeue |
| 2792 | auto index = firstIndex; |
| 2793 | BlockIndexHeader *localBlockIndex; |
| 2794 | auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); |
| 2795 | do { |
| 2796 | auto blockStartIndex = index; |
| 2797 | auto endIndex = |
| 2798 | (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE); |
| 2799 | endIndex = details::circular_less_than<index_t>( |
| 2800 | firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + |
| 2801 | static_cast<index_t>(actualCount) |
| 2802 | : endIndex; |
| 2803 | |
| 2804 | auto entry = localBlockIndex->index[indexIndex]; |
| 2805 | auto block = entry->value.load(std::memory_order_relaxed); |
| 2806 | if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T &&, details::deref_noexcept(itemFirst) = std::move( |
| 2807 | (*(*block)[index])))) { |
| 2808 | while (index != endIndex) { |
| 2809 | auto &el = *((*block)[index]); |
| 2810 | *itemFirst++ = std::move(el); |
| 2811 | el.~T(); |
| 2812 | ++index; |
| 2813 | } |
| 2814 | } else { |
| 2815 | MOODYCAMEL_TRY { |
| 2816 | while (index != endIndex) { |
| 2817 | auto &el = *((*block)[index]); |
| 2818 | *itemFirst = std::move(el); |
| 2819 | ++itemFirst; |
| 2820 | el.~T(); |
| 2821 | ++index; |
| 2822 | } |
nothing calls this directly
no test coverage detected