210 using value_type = T;
211 using reference = T&;
212 using const_reference = T
const&;
214 using size_type = std::size_t;
215 using difference_type = std::ptrdiff_t;
217 using allocator_type = Allocator;
220 using vector_type = std::vector<value_type, allocator_type>;
226 my_aggregator.initialize_handler(functor{
this});
234 my_aggregator.initialize_handler(functor{
this});
242 c.reserve(init_capacity);
243 my_aggregator.initialize_handler(functor{
this});
247 size_type init_capacity,
248 Compare
const& compare,
249 allocator_type
const& alloc = allocator_type()
255 c.reserve(init_capacity);
256 my_aggregator.initialize_handler(functor{
this});
259 template <
typename InputIterator>
263 Compare
const& compare,
264 allocator_type
const& alloc = allocator_type()
268 c(begin, end, alloc) {
269 my_aggregator.initialize_handler(functor{
this});
271 my_size.store(
c.size(), std::memory_order_relaxed);
274 template <
typename InputIterator>
279 std::initializer_list<value_type> init,
280 Compare
const& compare,
281 allocator_type
const& alloc = allocator_type()
290 my_size(other.my_size.load(std::memory_order_relaxed)),
291 my_compare(other.my_compare),
293 my_aggregator.initialize_handler(functor{
this});
298 my_size(other.my_size.load(std::memory_order_relaxed)),
299 my_compare(other.my_compare),
301 my_aggregator.initialize_handler(functor{
this});
306 my_size(other.my_size.load(std::memory_order_relaxed)),
307 my_compare(other.my_compare),
308 c(std::move(other.
c)) {
309 my_aggregator.initialize_handler(functor{
this});
314 my_size(other.my_size.load(std::memory_order_relaxed)),
315 my_compare(other.my_compare),
316 c(std::move(other.
c), alloc) {
317 my_aggregator.initialize_handler(functor{
this});
321 if (
this != &other) {
324 my_size.store(other.my_size.load(std::memory_order_relaxed), std::memory_order_relaxed);
330 if (
this != &other) {
331 c = std::move(other.
c);
333 my_size.store(other.my_size.load(std::memory_order_relaxed), std::memory_order_relaxed);
339 assign(init.begin(), init.end());
343 template <
typename InputIterator>
344 void assign(InputIterator begin, InputIterator end) {
345 c.assign(begin, end);
347 my_size.store(
c.size(), std::memory_order_relaxed);
351 void assign(std::initializer_list<value_type> init) { assign(init.begin(), init.end()); }
356 my_size.store(
c.size(), std::memory_order_relaxed);
363 [[nodiscard]]
bool empty()
const {
return size() == 0; }
368 size_type size()
const {
return my_size.load(std::memory_order_relaxed); }
371 void push(value_type
const& value)
372 requires(std::is_copy_constructible_v<value_type>)
374 cpq_operation op_data(value, PUSH_OP);
375 my_aggregator.execute(&op_data);
376 if (op_data.status == FAILED)
throw std::bad_alloc{};
380 void push(value_type&& value) {
381 cpq_operation op_data(value, PUSH_RVALUE_OP);
382 my_aggregator.execute(&op_data);
383 if (op_data.status == FAILED)
throw std::bad_alloc{};
387 template <
typename... Args>
388 void emplace(Args&&... args) {
389 push(value_type(std::forward<Args>(args)...));
396 bool try_pop(value_type& value) {
397 cpq_operation op_data(value, POP_OP);
398 my_aggregator.execute(&op_data);
399 return op_data.status == SUCCEEDED;
403 bool try_pop_if(F&& fn) {
404 function_data fn_data{(
void*)std::addressof(fn), +[](
void* f, value_type& value) ->
bool {
405 return std::invoke(
static_cast<F&&
>(*((F*)f)), value);
407 cpq_operation op_data(fn_data, POP_FN_OP);
408 my_aggregator.execute(&op_data);
409 return op_data.status == SUCCEEDED;
416 my_size.store(0, std::memory_order_relaxed);
421 if (
this != &other) {
424 swap(mark, other.mark);
426 size_type sz = my_size.load(std::memory_order_relaxed);
427 my_size.store(other.my_size.load(std::memory_order_relaxed), std::memory_order_relaxed);
428 other.my_size.store(sz, std::memory_order_relaxed);
432 allocator_type get_allocator()
const {
return c.get_allocator(); }
435 enum operation_type { PUSH_OP, PUSH_RVALUE_OP, POP_OP, POP_FN_OP };
436 enum operation_status { WAIT = 0, SUCCEEDED, FAILED };
438 struct function_data {
439 using function_type = bool(
void*, value_type&);
443 bool operator()(value_type& val)
const {
return func(data, val); }
450 function_data
const* fn;
453 cpq_operation(value_type
const& value, operation_type t) : type(t), elem(
const_cast<value_type*
>(&value)) {}
455 cpq_operation(function_data
const& f, operation_type t) : type(t), fn(&f) {}
462 functor() : my_cpq(
nullptr) {}
465 void operator()(cpq_operation* op_list) { my_cpq->handle_operations(op_list); }
468 void handle_operations(cpq_operation* op_list) {
469 cpq_operation *tmp, *pop_list =
nullptr;
482 op_list = op_list->next.load(std::memory_order_relaxed);
487 if constexpr (std::is_copy_constructible_v<value_type>) {
488 c.push_back(*(tmp->elem));
490 my_size.store(my_size.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
491 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
493 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
498 c.push_back(std::move(*(tmp->elem)));
499 my_size.store(my_size.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
500 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
502 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
506 if (mark <
c.size() && my_compare(
c[0],
c.back())) {
508 *(tmp->elem) = std::move(
c.back());
509 my_size.store(my_size.load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
510 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
513 tmp->next.store(pop_list, std::memory_order_relaxed);
518 if (mark <
c.size() && my_compare(
c[0],
c.back())) {
520 if ((*(tmp->fn))(
c.back())) {
521 my_size.store(my_size.load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
522 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
525 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
528 tmp->next.store(pop_list, std::memory_order_relaxed);
540 pop_list = pop_list->next.load(std::memory_order_relaxed);
542 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
544 if (mark <
c.size() && my_compare(
c[0],
c.back())) {
546 if (tmp->type == POP_FN_OP ? ((*(tmp->fn))(
c.back()))
547 : (*(tmp->elem) = std::move(
c.back()),
true)) {
548 my_size.store(my_size.load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
549 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
552 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
555 if (tmp->type == POP_FN_OP ? ((*(tmp->fn))(
c[0])) : (*(tmp->elem) = std::move(
c[0]),
true)) {
556 my_size.store(my_size.load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
557 tmp->status.store(uintptr_t(SUCCEEDED), std::memory_order_release);
560 tmp->status.store(uintptr_t(FAILED), std::memory_order_release);
568 if (mark <
c.size()) heapify();
573 if (!mark &&
c.size() > 0) mark = 1;
574 for (; mark <
c.size(); ++mark) {
576 size_type cur_pos = mark;
577 value_type to_place = std::move(
c[mark]);
579 size_type parent = (cur_pos - 1) >> 1;
580 if (!my_compare(
c[parent], to_place))
break;
581 c[cur_pos] = std::move(
c[parent]);
584 c[cur_pos] = std::move(to_place);
591 size_type cur_pos = 0, child = 1;
593 while (child < mark) {
594 size_type target = child;
595 if (child + 1 < mark && my_compare(
c[child],
c[child + 1])) ++target;
597 if (my_compare(
c[target],
c.back()))
break;
598 c[cur_pos] = std::move(
c[target]);
600 child = (cur_pos << 1) + 1;
602 if (cur_pos !=
c.size() - 1)
c[cur_pos] = std::move(
c.back());
604 if (mark >
c.size()) mark =
c.size();
614 std::atomic<size_type> my_size;
618 char padding2[max_nfs_size - (2 *
sizeof(size_type)) -
sizeof(Compare) % max_nfs_size];
642 return lhs.
c == rhs.
c;