Skip to content

Commit 961847f

Browse files
author
Maxim Egorushkin
committed
Always inline push and pop functions with gcc and clang to prevent compilers from emitting unnecessary external definitions.
1 parent 6005ada commit 961847f

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

include/atomic_queue/atomic_queue.h

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class AtomicQueueCommon {
176176
}
177177

178178
template<class T, T NIL>
179-
static T do_pop_atomic(std::atomic<T>& q_element) noexcept {
179+
ATOMIC_QUEUE_INLINE static T do_pop_atomic(std::atomic<T>& q_element) noexcept {
180180
if(Derived::spsc_) {
181181
for(;;) {
182182
T element = q_element.load(A);
@@ -202,7 +202,7 @@ class AtomicQueueCommon {
202202
}
203203

204204
template<class T, T NIL>
205-
static void do_push_atomic(T element, std::atomic<T>& q_element) noexcept {
205+
ATOMIC_QUEUE_INLINE static void do_push_atomic(T element, std::atomic<T>& q_element) noexcept {
206206
assert(element != NIL);
207207
if(Derived::spsc_) {
208208
while(ATOMIC_QUEUE_UNLIKELY(q_element.load(X) != NIL))
@@ -222,7 +222,7 @@ class AtomicQueueCommon {
222222
enum State : unsigned char { EMPTY, STORING, STORED, LOADING };
223223

224224
template<class T>
225-
static T do_pop_any(std::atomic<unsigned char>& state, T& q_element) noexcept {
225+
ATOMIC_QUEUE_INLINE static T do_pop_any(std::atomic<unsigned char>& state, T& q_element) noexcept {
226226
if(Derived::spsc_) {
227227
while(ATOMIC_QUEUE_UNLIKELY(state.load(A) != STORED))
228228
if(Derived::maximize_throughput_)
@@ -248,7 +248,7 @@ class AtomicQueueCommon {
248248
}
249249

250250
template<class U, class T>
251-
static void do_push_any(U&& element, std::atomic<unsigned char>& state, T& q_element) noexcept {
251+
ATOMIC_QUEUE_INLINE static void do_push_any(U&& element, std::atomic<unsigned char>& state, T& q_element) noexcept {
252252
if(Derived::spsc_) {
253253
while(ATOMIC_QUEUE_UNLIKELY(state.load(A) != EMPTY))
254254
if(Derived::maximize_throughput_)
@@ -274,7 +274,7 @@ class AtomicQueueCommon {
274274

275275
public:
276276
template<class T>
277-
bool try_push(T&& element) noexcept {
277+
ATOMIC_QUEUE_INLINE bool try_push(T&& element) noexcept {
278278
auto head = head_.load(X);
279279
if(Derived::spsc_) {
280280
if(static_cast<int>(head - tail_.load(X)) >= static_cast<int>(static_cast<Derived&>(*this).size_))
@@ -293,7 +293,7 @@ class AtomicQueueCommon {
293293
}
294294

295295
template<class T>
296-
bool try_pop(T& element) noexcept {
296+
ATOMIC_QUEUE_INLINE bool try_pop(T& element) noexcept {
297297
auto tail = tail_.load(X);
298298
if(Derived::spsc_) {
299299
if(static_cast<int>(head_.load(X) - tail) <= 0)
@@ -312,7 +312,7 @@ class AtomicQueueCommon {
312312
}
313313

314314
template<class T>
315-
void push(T&& element) noexcept {
315+
ATOMIC_QUEUE_INLINE void push(T&& element) noexcept {
316316
unsigned head;
317317
if(Derived::spsc_) {
318318
head = head_.load(X);
@@ -325,7 +325,7 @@ class AtomicQueueCommon {
325325
static_cast<Derived&>(*this).do_push(std::forward<T>(element), head);
326326
}
327327

328-
auto pop() noexcept {
328+
ATOMIC_QUEUE_INLINE auto pop() noexcept {
329329
unsigned tail;
330330
if(Derived::spsc_) {
331331
tail = tail_.load(X);
@@ -338,21 +338,21 @@ class AtomicQueueCommon {
338338
return static_cast<Derived&>(*this).do_pop(tail);
339339
}
340340

341-
bool was_empty() const noexcept {
341+
ATOMIC_QUEUE_INLINE bool was_empty() const noexcept {
342342
return !was_size();
343343
}
344344

345-
bool was_full() const noexcept {
345+
ATOMIC_QUEUE_INLINE bool was_full() const noexcept {
346346
return was_size() >= capacity();
347347
}
348348

349-
unsigned was_size() const noexcept {
349+
ATOMIC_QUEUE_INLINE unsigned was_size() const noexcept {
350350
// tail_ can be greater than head_ because of consumers doing pop, rather that try_pop, when the queue is empty.
351351
unsigned n{head_.load(X) - tail_.load(X)};
352352
return static_cast<int>(n) < 0 ? 0 : n; // Windows headers break std::min/max by default. Do std::max<int>(n, 0) the hard way here.
353353
}
354354

355-
unsigned capacity() const noexcept {
355+
ATOMIC_QUEUE_INLINE unsigned capacity() const noexcept {
356356
return static_cast<Derived const&>(*this).size_;
357357
}
358358
};
@@ -372,12 +372,12 @@ class AtomicQueue : public AtomicQueueCommon<AtomicQueue<T, SIZE, NIL, MINIMIZE_
372372

373373
alignas(CACHE_LINE_SIZE) std::atomic<T> elements_[size_];
374374

375-
T do_pop(unsigned tail) noexcept {
375+
ATOMIC_QUEUE_INLINE T do_pop(unsigned tail) noexcept {
376376
std::atomic<T>& q_element = details::map<SHUFFLE_BITS>(elements_, tail % size_);
377377
return Base::template do_pop_atomic<T, NIL>(q_element);
378378
}
379379

380-
void do_push(T element, unsigned head) noexcept {
380+
ATOMIC_QUEUE_INLINE void do_push(T element, unsigned head) noexcept {
381381
std::atomic<T>& q_element = details::map<SHUFFLE_BITS>(elements_, head % size_);
382382
Base::template do_push_atomic<T, NIL>(element, q_element);
383383
}
@@ -412,13 +412,13 @@ class AtomicQueue2 : public AtomicQueueCommon<AtomicQueue2<T, SIZE, MINIMIZE_CON
412412
alignas(CACHE_LINE_SIZE) std::atomic<unsigned char> states_[size_] = {};
413413
alignas(CACHE_LINE_SIZE) T elements_[size_] = {};
414414

415-
T do_pop(unsigned tail) noexcept {
415+
ATOMIC_QUEUE_INLINE T do_pop(unsigned tail) noexcept {
416416
unsigned index = details::remap_index<SHUFFLE_BITS>(tail % size_);
417417
return Base::do_pop_any(states_[index], elements_[index]);
418418
}
419419

420420
template<class U>
421-
void do_push(U&& element, unsigned head) noexcept {
421+
ATOMIC_QUEUE_INLINE void do_push(U&& element, unsigned head) noexcept {
422422
unsigned index = details::remap_index<SHUFFLE_BITS>(head % size_);
423423
Base::do_push_any(std::forward<U>(element), states_[index], elements_[index]);
424424
}
@@ -455,12 +455,12 @@ class AtomicQueueB : private std::allocator_traits<A>::template rebind_alloc<std
455455
alignas(CACHE_LINE_SIZE) unsigned size_;
456456
std::atomic<T>* elements_;
457457

458-
T do_pop(unsigned tail) noexcept {
458+
ATOMIC_QUEUE_INLINE T do_pop(unsigned tail) noexcept {
459459
std::atomic<T>& q_element = details::map<SHUFFLE_BITS>(elements_, tail & (size_ - 1));
460460
return Base::template do_pop_atomic<T, NIL>(q_element);
461461
}
462462

463-
void do_push(T element, unsigned head) noexcept {
463+
ATOMIC_QUEUE_INLINE void do_push(T element, unsigned head) noexcept {
464464
std::atomic<T>& q_element = details::map<SHUFFLE_BITS>(elements_, head & (size_ - 1));
465465
Base::template do_push_atomic<T, NIL>(element, q_element);
466466
}
@@ -543,13 +543,13 @@ class AtomicQueueB2 : private std::allocator_traits<A>::template rebind_alloc<un
543543
static constexpr auto SHUFFLE_BITS = details::GetCacheLineIndexBits<STATES_PER_CACHE_LINE>::value;
544544
static_assert(SHUFFLE_BITS, "Unexpected SHUFFLE_BITS.");
545545

546-
T do_pop(unsigned tail) noexcept {
546+
ATOMIC_QUEUE_INLINE T do_pop(unsigned tail) noexcept {
547547
unsigned index = details::remap_index<SHUFFLE_BITS>(tail & (size_ - 1));
548548
return Base::do_pop_any(states_[index], elements_[index]);
549549
}
550550

551551
template<class U>
552-
void do_push(U&& element, unsigned head) noexcept {
552+
ATOMIC_QUEUE_INLINE void do_push(U&& element, unsigned head) noexcept {
553553
unsigned index = details::remap_index<SHUFFLE_BITS>(head & (size_ - 1));
554554
Base::do_push_any(std::forward<U>(element), states_[index], elements_[index]);
555555
}
@@ -634,12 +634,12 @@ struct RetryDecorator : Queue {
634634

635635
using Queue::Queue;
636636

637-
void push(T element) noexcept {
637+
ATOMIC_QUEUE_INLINE void push(T element) noexcept {
638638
while(!this->try_push(element))
639639
spin_loop_pause();
640640
}
641641

642-
T pop() noexcept {
642+
ATOMIC_QUEUE_INLINE T pop() noexcept {
643643
T element;
644644
while(!this->try_pop(element))
645645
spin_loop_pause();

0 commit comments

Comments
 (0)