Coverage Report

Created: 2026-09-14 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ocudu/external/rigtorp/MPMCQueue.h
Line
Count
Source
1
/*
2
Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
3
4
Permission is hereby granted, free of charge, to any person obtaining a copy
5
of this software and associated documentation files (the "Software"), to deal
6
in the Software without restriction, including without limitation the rights
7
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
copies of the Software, and to permit persons to whom the Software is
9
furnished to do so, subject to the following conditions:
10
11
The above copyright notice and this permission notice shall be included in all
12
copies or substantial portions of the Software.
13
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
SOFTWARE.
21
 */
22
23
#pragma once
24
25
#include <atomic>
26
#include <cassert>
27
#include <cstddef> // offsetof
28
#include <limits>
29
#include <memory>
30
#include <new> // std::hardware_destructive_interference_size
31
#include <stdexcept>
32
33
#ifndef __cpp_aligned_new
34
#ifdef _WIN32
35
#include <malloc.h> // _aligned_malloc
36
#else
37
#include <stdlib.h> // posix_memalign
38
#endif
39
#endif
40
41
namespace rigtorp {
42
namespace mpmc {
43
static constexpr size_t hardwareInterferenceSize = 64;
44
45
#if defined(__cpp_aligned_new)
46
template <typename T> using AlignedAllocator = std::allocator<T>;
47
#else
48
template <typename T> struct AlignedAllocator {
49
  using value_type = T;
50
51
  T *allocate(std::size_t n) {
52
    if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) {
53
      throw std::bad_array_new_length();
54
    }
55
#ifdef _WIN32
56
    auto *p = static_cast<T *>(_aligned_malloc(sizeof(T) * n, alignof(T)));
57
    if (p == nullptr) {
58
      throw std::bad_alloc();
59
    }
60
#else
61
    T *p;
62
    if (posix_memalign(reinterpret_cast<void **>(&p), alignof(T),
63
                       sizeof(T) * n) != 0) {
64
      throw std::bad_alloc();
65
    }
66
#endif
67
    return p;
68
  }
69
70
  void deallocate(T *p, std::size_t) {
71
#ifdef _WIN32
72
    _aligned_free(p);
73
#else
74
    free(p);
75
#endif
76
  }
77
};
78
#endif
79
80
template <typename T> struct Slot {
81
163k
  ~Slot() noexcept {
82
163k
    if (turn & 1) {
83
81.9k
      destroy();
84
81.9k
    }
85
163k
  }
rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>::~Slot()
Line
Count
Source
81
81.9k
  ~Slot() noexcept {
82
81.9k
    if (turn & 1) {
83
65.5k
      destroy();
84
65.5k
    }
85
81.9k
  }
rigtorp::mpmc::Slot<ocudulog::detail::log_entry>::~Slot()
Line
Count
Source
81
81.9k
  ~Slot() noexcept {
82
81.9k
    if (turn & 1) {
83
16.3k
      destroy();
84
16.3k
    }
85
81.9k
  }
Unexecuted instantiation: rigtorp::mpmc::Slot<unsigned int>::~Slot()
Unexecuted instantiation: rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> >::~Slot()
86
87
98.3k
  template <typename... Args> void construct(Args &&...args) noexcept {
88
98.3k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
89
98.3k
                  "T must be nothrow constructible with Args&&...");
90
98.3k
    new (&storage) T(std::forward<Args>(args)...);
91
98.3k
  }
void rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>::construct<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&&)
Line
Count
Source
87
81.9k
  template <typename... Args> void construct(Args &&...args) noexcept {
88
81.9k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
89
81.9k
                  "T must be nothrow constructible with Args&&...");
90
81.9k
    new (&storage) T(std::forward<Args>(args)...);
91
81.9k
  }
void rigtorp::mpmc::Slot<ocudulog::detail::log_entry>::construct<ocudulog::detail::log_entry>(ocudulog::detail::log_entry&&)
Line
Count
Source
87
16.3k
  template <typename... Args> void construct(Args &&...args) noexcept {
88
16.3k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
89
16.3k
                  "T must be nothrow constructible with Args&&...");
90
16.3k
    new (&storage) T(std::forward<Args>(args)...);
91
16.3k
  }
Unexecuted instantiation: void rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>::construct<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&)
Unexecuted instantiation: void rigtorp::mpmc::Slot<unsigned int>::construct<unsigned int const&>(unsigned int const&)
Unexecuted instantiation: void rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> >::construct<ocudu::unique_function<void (), 64ul, false> >(ocudu::unique_function<void (), 64ul, false>&&)
92
93
98.3k
  void destroy() noexcept {
94
98.3k
    static_assert(std::is_nothrow_destructible<T>::value,
95
98.3k
                  "T must be nothrow destructible");
96
98.3k
    std::launder(reinterpret_cast<T *>(&storage))->~T();
97
98.3k
  }
rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>::destroy()
Line
Count
Source
93
81.9k
  void destroy() noexcept {
94
81.9k
    static_assert(std::is_nothrow_destructible<T>::value,
95
81.9k
                  "T must be nothrow destructible");
96
81.9k
    std::launder(reinterpret_cast<T *>(&storage))->~T();
97
81.9k
  }
rigtorp::mpmc::Slot<ocudulog::detail::log_entry>::destroy()
Line
Count
Source
93
16.3k
  void destroy() noexcept {
94
16.3k
    static_assert(std::is_nothrow_destructible<T>::value,
95
16.3k
                  "T must be nothrow destructible");
96
16.3k
    std::launder(reinterpret_cast<T *>(&storage))->~T();
97
16.3k
  }
Unexecuted instantiation: rigtorp::mpmc::Slot<unsigned int>::destroy()
Unexecuted instantiation: rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> >::destroy()
98
99
16.3k
  T &&move() noexcept {
100
16.3k
    return std::move(*std::launder(reinterpret_cast<T *>(&storage)));
101
16.3k
  }
rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>::move()
Line
Count
Source
99
16.3k
  T &&move() noexcept {
100
16.3k
    return std::move(*std::launder(reinterpret_cast<T *>(&storage)));
101
16.3k
  }
Unexecuted instantiation: rigtorp::mpmc::Slot<ocudulog::detail::log_entry>::move()
Unexecuted instantiation: rigtorp::mpmc::Slot<unsigned int>::move()
Unexecuted instantiation: rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> >::move()
102
103
  // Align to avoid false sharing between adjacent slots
104
  alignas(hardwareInterferenceSize) std::atomic<size_t> turn = {0};
105
  typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
106
};
107
108
template <typename T, typename Allocator = AlignedAllocator<Slot<T>>>
109
class Queue {
110
private:
111
  static_assert(std::is_nothrow_copy_assignable<T>::value ||
112
                    std::is_nothrow_move_assignable<T>::value,
113
                "T must be nothrow copy or move assignable");
114
115
  static_assert(std::is_nothrow_destructible<T>::value,
116
                "T must be nothrow destructible");
117
118
public:
119
  explicit Queue(const size_t capacity,
120
                 const Allocator &allocator = Allocator())
121
20
      : capacity_(capacity), allocator_(allocator), head_(0), tail_(0) {
122
20
    if (capacity_ < 1) {
123
0
      throw std::invalid_argument("capacity < 1");
124
0
    }
125
    // Allocate one extra slot to prevent false sharing on the last slot
126
20
    slots_ = allocator_.allocate(capacity_ + 1);
127
    // Allocators are not required to honor alignment for over-aligned types
128
    // (see http://eel.is/c++draft/allocator.requirements#10) so we verify
129
    // alignment here
130
20
    if (reinterpret_cast<size_t>(slots_) % alignof(Slot<T>) != 0) {
131
0
      allocator_.deallocate(slots_, capacity_ + 1);
132
0
      throw std::bad_alloc();
133
0
    }
134
163k
    for (size_t i = 0; i < capacity_; ++i) {
135
163k
      new (&slots_[i]) Slot<T>();
136
163k
    }
137
20
    static_assert(
138
20
        alignof(Slot<T>) == hardwareInterferenceSize,
139
20
        "Slot must be aligned to cache line boundary to prevent false sharing");
140
20
    static_assert(sizeof(Slot<T>) % hardwareInterferenceSize == 0,
141
20
                  "Slot size must be a multiple of cache line size to prevent "
142
20
                  "false sharing between adjacent slots");
143
20
    static_assert(sizeof(Queue) % hardwareInterferenceSize == 0,
144
20
                  "Queue size must be a multiple of cache line size to "
145
20
                  "prevent false sharing between adjacent queues");
146
20
    static_assert(
147
20
        offsetof(Queue, tail_) - offsetof(Queue, head_) ==
148
20
            static_cast<std::ptrdiff_t>(hardwareInterferenceSize),
149
20
        "head and tail must be a cache line apart to prevent false sharing");
150
20
  }
rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::Queue(unsigned long, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > const&)
Line
Count
Source
121
10
      : capacity_(capacity), allocator_(allocator), head_(0), tail_(0) {
122
10
    if (capacity_ < 1) {
123
0
      throw std::invalid_argument("capacity < 1");
124
0
    }
125
    // Allocate one extra slot to prevent false sharing on the last slot
126
10
    slots_ = allocator_.allocate(capacity_ + 1);
127
    // Allocators are not required to honor alignment for over-aligned types
128
    // (see http://eel.is/c++draft/allocator.requirements#10) so we verify
129
    // alignment here
130
10
    if (reinterpret_cast<size_t>(slots_) % alignof(Slot<T>) != 0) {
131
0
      allocator_.deallocate(slots_, capacity_ + 1);
132
0
      throw std::bad_alloc();
133
0
    }
134
81.9k
    for (size_t i = 0; i < capacity_; ++i) {
135
81.9k
      new (&slots_[i]) Slot<T>();
136
81.9k
    }
137
10
    static_assert(
138
10
        alignof(Slot<T>) == hardwareInterferenceSize,
139
10
        "Slot must be aligned to cache line boundary to prevent false sharing");
140
10
    static_assert(sizeof(Slot<T>) % hardwareInterferenceSize == 0,
141
10
                  "Slot size must be a multiple of cache line size to prevent "
142
10
                  "false sharing between adjacent slots");
143
10
    static_assert(sizeof(Queue) % hardwareInterferenceSize == 0,
144
10
                  "Queue size must be a multiple of cache line size to "
145
10
                  "prevent false sharing between adjacent queues");
146
10
    static_assert(
147
10
        offsetof(Queue, tail_) - offsetof(Queue, head_) ==
148
10
            static_cast<std::ptrdiff_t>(hardwareInterferenceSize),
149
10
        "head and tail must be a cache line apart to prevent false sharing");
150
10
  }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::Queue(unsigned long, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > const&)
Line
Count
Source
121
10
      : capacity_(capacity), allocator_(allocator), head_(0), tail_(0) {
122
10
    if (capacity_ < 1) {
123
0
      throw std::invalid_argument("capacity < 1");
124
0
    }
125
    // Allocate one extra slot to prevent false sharing on the last slot
126
10
    slots_ = allocator_.allocate(capacity_ + 1);
127
    // Allocators are not required to honor alignment for over-aligned types
128
    // (see http://eel.is/c++draft/allocator.requirements#10) so we verify
129
    // alignment here
130
10
    if (reinterpret_cast<size_t>(slots_) % alignof(Slot<T>) != 0) {
131
0
      allocator_.deallocate(slots_, capacity_ + 1);
132
0
      throw std::bad_alloc();
133
0
    }
134
81.9k
    for (size_t i = 0; i < capacity_; ++i) {
135
81.9k
      new (&slots_[i]) Slot<T>();
136
81.9k
    }
137
10
    static_assert(
138
10
        alignof(Slot<T>) == hardwareInterferenceSize,
139
10
        "Slot must be aligned to cache line boundary to prevent false sharing");
140
10
    static_assert(sizeof(Slot<T>) % hardwareInterferenceSize == 0,
141
10
                  "Slot size must be a multiple of cache line size to prevent "
142
10
                  "false sharing between adjacent slots");
143
10
    static_assert(sizeof(Queue) % hardwareInterferenceSize == 0,
144
10
                  "Queue size must be a multiple of cache line size to "
145
10
                  "prevent false sharing between adjacent queues");
146
10
    static_assert(
147
10
        offsetof(Queue, tail_) - offsetof(Queue, head_) ==
148
10
            static_cast<std::ptrdiff_t>(hardwareInterferenceSize),
149
10
        "head and tail must be a cache line apart to prevent false sharing");
150
10
  }
Unexecuted instantiation: rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::Queue(unsigned long, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > const&)
151
152
20
  ~Queue() noexcept {
153
163k
    for (size_t i = 0; i < capacity_; ++i) {
154
163k
      slots_[i].~Slot();
155
163k
    }
156
20
    allocator_.deallocate(slots_, capacity_ + 1);
157
20
  }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::~Queue()
Line
Count
Source
152
10
  ~Queue() noexcept {
153
81.9k
    for (size_t i = 0; i < capacity_; ++i) {
154
81.9k
      slots_[i].~Slot();
155
81.9k
    }
156
10
    allocator_.deallocate(slots_, capacity_ + 1);
157
10
  }
rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::~Queue()
Line
Count
Source
152
10
  ~Queue() noexcept {
153
81.9k
    for (size_t i = 0; i < capacity_; ++i) {
154
81.9k
      slots_[i].~Slot();
155
81.9k
    }
156
10
    allocator_.deallocate(slots_, capacity_ + 1);
157
10
  }
Unexecuted instantiation: rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::~Queue()
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::~Queue()
158
159
  // non-copyable and non-movable
160
  Queue(const Queue &) = delete;
161
  Queue &operator=(const Queue &) = delete;
162
163
81.9k
  template <typename... Args> void emplace(Args &&...args) noexcept {
164
81.9k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
165
81.9k
                  "T must be nothrow constructible with Args&&...");
166
81.9k
    auto const head = head_.fetch_add(1);
167
81.9k
    auto &slot = slots_[idx(head)];
168
81.9k
    while (turn(head) * 2 != slot.turn.load(std::memory_order_acquire))
169
0
      ;
170
81.9k
    slot.construct(std::forward<Args>(args)...);
171
81.9k
    slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
172
81.9k
  }
void rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::emplace<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&&)
Line
Count
Source
163
81.9k
  template <typename... Args> void emplace(Args &&...args) noexcept {
164
81.9k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
165
81.9k
                  "T must be nothrow constructible with Args&&...");
166
81.9k
    auto const head = head_.fetch_add(1);
167
81.9k
    auto &slot = slots_[idx(head)];
168
81.9k
    while (turn(head) * 2 != slot.turn.load(std::memory_order_acquire))
169
0
      ;
170
81.9k
    slot.construct(std::forward<Args>(args)...);
171
81.9k
    slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
172
81.9k
  }
Unexecuted instantiation: void rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::emplace<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&)
173
174
16.3k
  template <typename... Args> bool try_emplace(Args &&...args) noexcept {
175
16.3k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
176
16.3k
                  "T must be nothrow constructible with Args&&...");
177
16.3k
    auto head = head_.load(std::memory_order_acquire);
178
16.3k
    for (;;) {
179
16.3k
      auto &slot = slots_[idx(head)];
180
16.3k
      if (turn(head) * 2 == slot.turn.load(std::memory_order_acquire)) {
181
16.3k
        if (head_.compare_exchange_strong(head, head + 1)) {
182
16.3k
          slot.construct(std::forward<Args>(args)...);
183
16.3k
          slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
184
16.3k
          return true;
185
16.3k
        }
186
16.3k
      } else {
187
0
        auto const prevHead = head;
188
0
        head = head_.load(std::memory_order_acquire);
189
0
        if (head == prevHead) {
190
0
          return false;
191
0
        }
192
0
      }
193
16.3k
    }
194
16.3k
  }
bool rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::try_emplace<ocudulog::detail::log_entry>(ocudulog::detail::log_entry&&)
Line
Count
Source
174
16.3k
  template <typename... Args> bool try_emplace(Args &&...args) noexcept {
175
16.3k
    static_assert(std::is_nothrow_constructible<T, Args &&...>::value,
176
16.3k
                  "T must be nothrow constructible with Args&&...");
177
16.3k
    auto head = head_.load(std::memory_order_acquire);
178
16.3k
    for (;;) {
179
16.3k
      auto &slot = slots_[idx(head)];
180
16.3k
      if (turn(head) * 2 == slot.turn.load(std::memory_order_acquire)) {
181
16.3k
        if (head_.compare_exchange_strong(head, head + 1)) {
182
16.3k
          slot.construct(std::forward<Args>(args)...);
183
16.3k
          slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
184
16.3k
          return true;
185
16.3k
        }
186
16.3k
      } else {
187
0
        auto const prevHead = head;
188
0
        head = head_.load(std::memory_order_acquire);
189
0
        if (head == prevHead) {
190
0
          return false;
191
0
        }
192
0
      }
193
16.3k
    }
194
16.3k
  }
Unexecuted instantiation: bool rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::try_emplace<unsigned int const&>(unsigned int const&)
Unexecuted instantiation: bool rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::try_emplace<ocudu::unique_function<void (), 64ul, false> >(ocudu::unique_function<void (), 64ul, false>&&)
195
196
  void push(const T &v) noexcept {
197
    static_assert(std::is_nothrow_copy_constructible<T>::value,
198
                  "T must be nothrow copy constructible");
199
    emplace(v);
200
  }
201
202
  template <typename P,
203
            typename = typename std::enable_if<
204
                std::is_nothrow_constructible<T, P &&>::value>::type>
205
81.9k
  void push(P &&v) noexcept {
206
81.9k
    emplace(std::forward<P>(v));
207
81.9k
  }
void rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::push<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, void>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&&)
Line
Count
Source
205
81.9k
  void push(P &&v) noexcept {
206
81.9k
    emplace(std::forward<P>(v));
207
81.9k
  }
Unexecuted instantiation: void rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::push<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&, void>(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&)
208
209
0
  bool try_push(const T &v) noexcept {
210
0
    static_assert(std::is_nothrow_copy_constructible<T>::value,
211
0
                  "T must be nothrow copy constructible");
212
0
    return try_emplace(v);
213
0
  }
214
215
  template <typename P,
216
            typename = typename std::enable_if<
217
                std::is_nothrow_constructible<T, P &&>::value>::type>
218
16.3k
  bool try_push(P &&v) noexcept {
219
16.3k
    return try_emplace(std::forward<P>(v));
220
16.3k
  }
bool rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::try_push<ocudulog::detail::log_entry, void>(ocudulog::detail::log_entry&&)
Line
Count
Source
218
16.3k
  bool try_push(P &&v) noexcept {
219
16.3k
    return try_emplace(std::forward<P>(v));
220
16.3k
  }
Unexecuted instantiation: bool rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::try_push<ocudu::unique_function<void (), 64ul, false>, void>(ocudu::unique_function<void (), 64ul, false>&&)
221
222
  void pop(T &v) noexcept {
223
    auto const tail = tail_.fetch_add(1);
224
    auto &slot = slots_[idx(tail)];
225
    while (turn(tail) * 2 + 1 != slot.turn.load(std::memory_order_acquire))
226
      ;
227
    v = slot.move();
228
    slot.destroy();
229
    slot.turn.store(turn(tail) * 2 + 2, std::memory_order_release);
230
  }
231
232
16.3k
  bool try_pop(T &v) noexcept {
233
16.3k
    auto tail = tail_.load(std::memory_order_acquire);
234
16.3k
    for (;;) {
235
16.3k
      auto &slot = slots_[idx(tail)];
236
16.3k
      if (turn(tail) * 2 + 1 == slot.turn.load(std::memory_order_acquire)) {
237
16.3k
        if (tail_.compare_exchange_strong(tail, tail + 1)) {
238
16.3k
          v = slot.move();
239
16.3k
          slot.destroy();
240
16.3k
          slot.turn.store(turn(tail) * 2 + 2, std::memory_order_release);
241
16.3k
          return true;
242
16.3k
        }
243
16.3k
      } else {
244
0
        auto const prevTail = tail;
245
0
        tail = tail_.load(std::memory_order_acquire);
246
0
        if (tail == prevTail) {
247
0
          return false;
248
0
        }
249
0
      }
250
16.3k
    }
251
16.3k
  }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::try_pop(fmt::v11::dynamic_format_arg_store<fmt::v11::context>*&)
Line
Count
Source
232
16.3k
  bool try_pop(T &v) noexcept {
233
16.3k
    auto tail = tail_.load(std::memory_order_acquire);
234
16.3k
    for (;;) {
235
16.3k
      auto &slot = slots_[idx(tail)];
236
16.3k
      if (turn(tail) * 2 + 1 == slot.turn.load(std::memory_order_acquire)) {
237
16.3k
        if (tail_.compare_exchange_strong(tail, tail + 1)) {
238
16.3k
          v = slot.move();
239
16.3k
          slot.destroy();
240
16.3k
          slot.turn.store(turn(tail) * 2 + 2, std::memory_order_release);
241
16.3k
          return true;
242
16.3k
        }
243
16.3k
      } else {
244
0
        auto const prevTail = tail;
245
0
        tail = tail_.load(std::memory_order_acquire);
246
0
        if (tail == prevTail) {
247
0
          return false;
248
0
        }
249
0
      }
250
16.3k
    }
251
16.3k
  }
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::try_pop(ocudulog::detail::log_entry&)
Unexecuted instantiation: rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::try_pop(unsigned int&)
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::try_pop(ocudu::unique_function<void (), 64ul, false>&)
252
253
  /// Returns the number of elements in the queue.
254
  /// The size can be negative when the queue is empty and there is at least one
255
  /// reader waiting. Since this is a concurrent queue the size is only a best
256
  /// effort guess until all reader and writer threads have been joined.
257
431k
  ptrdiff_t size() const noexcept {
258
    // TODO: How can we deal with wrapped queue on 32bit?
259
431k
    return static_cast<ptrdiff_t>(head_.load(std::memory_order_relaxed) -
260
431k
                                  tail_.load(std::memory_order_relaxed));
261
431k
  }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::size() const
Line
Count
Source
257
431k
  ptrdiff_t size() const noexcept {
258
    // TODO: How can we deal with wrapped queue on 32bit?
259
431k
    return static_cast<ptrdiff_t>(head_.load(std::memory_order_relaxed) -
260
431k
                                  tail_.load(std::memory_order_relaxed));
261
431k
  }
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::size() const
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::size() const
262
263
  /// Returns true if the queue is empty.
264
  /// Since this is a concurrent queue this is only a best effort guess
265
  /// until all reader and writer threads have been joined.
266
431k
  bool empty() const noexcept { return size() <= 0; }
267
268
0
  size_t capacity() const noexcept { return capacity_; }
269
270
private:
271
114k
  constexpr size_t idx(size_t i) const noexcept { return i % capacity_; }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::idx(unsigned long) const
Line
Count
Source
271
98.3k
  constexpr size_t idx(size_t i) const noexcept { return i % capacity_; }
rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::idx(unsigned long) const
Line
Count
Source
271
16.3k
  constexpr size_t idx(size_t i) const noexcept { return i % capacity_; }
Unexecuted instantiation: rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::idx(unsigned long) const
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::idx(unsigned long) const
272
273
229k
  constexpr size_t turn(size_t i) const noexcept { return i / capacity_; }
rigtorp::mpmc::Queue<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*, std::__1::allocator<rigtorp::mpmc::Slot<fmt::v11::dynamic_format_arg_store<fmt::v11::context>*> > >::turn(unsigned long) const
Line
Count
Source
273
196k
  constexpr size_t turn(size_t i) const noexcept { return i / capacity_; }
rigtorp::mpmc::Queue<ocudulog::detail::log_entry, std::__1::allocator<rigtorp::mpmc::Slot<ocudulog::detail::log_entry> > >::turn(unsigned long) const
Line
Count
Source
273
32.7k
  constexpr size_t turn(size_t i) const noexcept { return i / capacity_; }
Unexecuted instantiation: rigtorp::mpmc::Queue<unsigned int, std::__1::allocator<rigtorp::mpmc::Slot<unsigned int> > >::turn(unsigned long) const
Unexecuted instantiation: rigtorp::mpmc::Queue<ocudu::unique_function<void (), 64ul, false>, std::__1::allocator<rigtorp::mpmc::Slot<ocudu::unique_function<void (), 64ul, false> > > >::turn(unsigned long) const
274
275
private:
276
  const size_t capacity_;
277
  Slot<T> *slots_;
278
#if defined(__has_cpp_attribute) && __has_cpp_attribute(no_unique_address)
279
  Allocator allocator_ [[no_unique_address]];
280
#else
281
  Allocator allocator_;
282
#endif
283
284
  // Align to avoid false sharing between head_ and tail_
285
  alignas(hardwareInterferenceSize) std::atomic<size_t> head_;
286
  alignas(hardwareInterferenceSize) std::atomic<size_t> tail_;
287
};
288
} // namespace mpmc
289
290
template <typename T,
291
          typename Allocator = mpmc::AlignedAllocator<mpmc::Slot<T>>>
292
using MPMCQueue = mpmc::Queue<T, Allocator>;
293
294
} // namespace rigtorp