| 2246 | |
| 2247 | template<typename It> |
| 2248 | size_t dequeue_bulk(It& itemFirst, size_t max) |
| 2249 | { |
| 2250 | auto tail = this->tailIndex.load(std::memory_order_relaxed); |
| 2251 | auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); |
| 2252 | auto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); |
| 2253 | if (details::circular_less_than<size_t>(0, desiredCount)) { |
| 2254 | desiredCount = desiredCount < max ? desiredCount : max; |
| 2255 | std::atomic_thread_fence(std::memory_order_acquire); |
| 2256 | |
| 2257 | auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); |
| 2258 | |
| 2259 | tail = this->tailIndex.load(std::memory_order_acquire); |
| 2260 | auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit)); |
| 2261 | if (details::circular_less_than<size_t>(0, actualCount)) { |
| 2262 | actualCount = desiredCount < actualCount ? desiredCount : actualCount; |
| 2263 | if (actualCount < desiredCount) { |
| 2264 | this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); |
| 2265 | } |
| 2266 | |
| 2267 | // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this |
| 2268 | // will never exceed tail. |
| 2269 | auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); |
| 2270 | |
| 2271 | // Determine which block the first element is in |
| 2272 | auto localBlockIndex = blockIndex.load(std::memory_order_acquire); |
| 2273 | auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); |
| 2274 | |
| 2275 | auto headBase = localBlockIndex->entries[localBlockIndexHead].base; |
| 2276 | auto firstBlockBaseIndex = firstIndex & ~static_cast<index_t>(BLOCK_SIZE - 1); |
| 2277 | auto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(firstBlockBaseIndex - headBase) / static_cast<typename std::make_signed<index_t>::type>(BLOCK_SIZE)); |
| 2278 | auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); |
| 2279 | |
| 2280 | // Iterate the blocks and dequeue |
| 2281 | auto index = firstIndex; |
| 2282 | do { |
| 2283 | auto firstIndexInBlock = index; |
| 2284 | index_t endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE); |
| 2285 | endIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex; |
| 2286 | auto block = localBlockIndex->entries[indexIndex].block; |
| 2287 | if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { |
| 2288 | while (index != endIndex) { |
| 2289 | auto& el = *((*block)[index]); |
| 2290 | *itemFirst++ = std::move(el); |
| 2291 | el.~T(); |
| 2292 | ++index; |
| 2293 | } |
| 2294 | } |
| 2295 | else { |
| 2296 | MOODYCAMEL_TRY { |
| 2297 | while (index != endIndex) { |
| 2298 | auto& el = *((*block)[index]); |
| 2299 | *itemFirst = std::move(el); |
| 2300 | ++itemFirst; |
| 2301 | el.~T(); |
| 2302 | ++index; |
| 2303 | } |
| 2304 | } |
| 2305 | MOODYCAMEL_CATCH (...) { |
nothing calls this directly
no test coverage detected