libtcspc C++ API
Streaming TCSPC and time tag data processing
Loading...
Searching...
No Matches
bucket.hpp
1/*
2 * This file is part of libtcspc
3 * Copyright 2019-2026 Board of Regents of the University of Wisconsin System
4 * SPDX-License-Identifier: MIT
5 */
6
7#pragma once
8
9#include "arg_wrappers.hpp"
10#include "errors.hpp"
11#include "introspect.hpp"
12#include "move_only_any.hpp"
13#include "processor.hpp"
14
15#include <algorithm>
16#include <cassert>
17#include <condition_variable>
18#include <cstddef>
19#include <functional>
20#include <limits>
21#include <memory>
22#include <mutex>
23#include <ostream>
24#include <span>
25#include <stdexcept>
26#include <type_traits>
27#include <typeinfo>
28#include <utility>
29#include <vector>
30
31namespace tcspc {
32
110template <typename T> class bucket {
111 struct owning_storage {
112 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
113 std::unique_ptr<T[]> p;
114
115 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
116 explicit owning_storage(std::unique_ptr<T[]> ptr)
117 : p(std::move(ptr)) {}
118 };
119
120 std::span<T> s;
121 internal::move_only_any store;
122
123 public:
127 bucket() noexcept = default;
128
136 template <typename S>
137 explicit bucket(std::span<T> span, S &&storage)
138 : s(span), store(std::forward<S>(storage)) {}
139
140 ~bucket() = default;
141
143 bucket(bucket const &other)
144 : store(std::invoke([&s = other.s] {
145 using TMut = std::remove_cv_t<T>;
146 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
147 std::unique_ptr<TMut[]> r(s.empty() ? nullptr
148 : new TMut[s.size()]);
149 std::copy(s.begin(), s.end(), r.get());
150 return internal::move_only_any(
151 std::in_place_type<owning_storage>, std::move(r));
152 })) {
153 T *ptr = internal::move_only_any_cast<owning_storage>(&store)->p.get();
154 s = {ptr, other.s.size()};
155 }
156
158 bucket(bucket &&other) noexcept = default;
159
161 auto operator=(bucket const &other) -> bucket & {
162 bucket t(other);
163 std::swap(*this, t);
164 return *this;
165 }
166
168 auto operator=(bucket &&other) noexcept -> bucket & = default;
169
170 // Equivalents of most of span's members follow. But many of the member
171 // functions are duplicated to work with a const bucket (because a const
172 // bucket has read-only data, unlike a const span).
173
175 using element_type = std::span<T>::element_type;
177 using value_type = std::span<T>::value_type;
179 using size_type = std::span<T>::size_type;
181 using difference_type = std::span<T>::difference_type;
183 using pointer = std::span<T>::pointer;
185 using const_pointer = std::span<T>::const_pointer;
187 using reference = std::span<T>::reference;
189 using const_reference = std::span<T>::const_reference;
191 using iterator = std::span<T>::iterator;
193 using const_iterator = std::span<T const>::iterator;
195 using reverse_iterator = std::span<T>::reverse_iterator;
197 using const_reverse_iterator = std::span<T const>::reverse_iterator;
198
200 [[nodiscard]] constexpr auto begin() noexcept -> iterator {
201 return s.begin();
202 }
203
205 [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator {
206 return std::span<T const>(s).begin();
207 }
208
210 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator {
211 return cbegin();
212 }
213
215 [[nodiscard]] constexpr auto end() noexcept -> iterator { return s.end(); }
216
218 [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator {
219 return std::span<T const>(s).end();
220 }
221
223 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator {
224 return cend();
225 }
226
228 [[nodiscard]] constexpr auto rbegin() noexcept -> reverse_iterator {
229 return s.rbegin();
230 }
231
233 [[nodiscard]] constexpr auto crbegin() const noexcept
235 return std::span<T const>(s).rbegin();
236 }
237
239 [[nodiscard]] constexpr auto rbegin() const noexcept
241 return crbegin();
242 }
243
245 [[nodiscard]] constexpr auto rend() noexcept -> reverse_iterator {
246 return s.rend();
247 }
248
250 [[nodiscard]] constexpr auto crend() const noexcept
252 return std::span<T const>(s).rend();
253 }
254
256 [[nodiscard]] constexpr auto rend() const noexcept
258 return crend();
259 }
260
262 [[nodiscard]] constexpr auto front() -> reference { return s.front(); }
263
265 [[nodiscard]] constexpr auto front() const -> const_reference {
266 return std::span<T const>(s).front();
267 }
268
270 [[nodiscard]] constexpr auto back() -> reference { return s.back(); }
271
273 [[nodiscard]] constexpr auto back() const -> const_reference {
274 return std::span<T const>(s).back();
275 }
276
278 [[nodiscard]] constexpr auto operator[](size_type idx) -> reference {
279 return s[idx];
280 }
281
283 [[nodiscard]] constexpr auto operator[](size_type idx) const
284 -> const_reference {
285 return s[idx];
286 }
287
289 [[nodiscard]] constexpr auto at(size_type pos) -> reference {
290 if (pos >= size())
291 throw std::out_of_range("bucket element index out of range");
292 return s[pos];
293 }
294
296 [[nodiscard]] constexpr auto at(size_type pos) const -> const_reference {
297 if (pos >= size())
298 throw std::out_of_range("bucket element index out of range");
299 return s[pos];
300 }
301
303 [[nodiscard]] constexpr auto data() noexcept -> pointer {
304 return s.data();
305 }
306
308 [[nodiscard]] constexpr auto data() const noexcept -> const_pointer {
309 return s.data();
310 }
311
313 [[nodiscard]] constexpr auto size() const noexcept -> size_type {
314 return s.size();
315 }
316
318 [[nodiscard]] constexpr auto size_bytes() const noexcept -> size_type {
319 return s.size_bytes();
320 }
321
323 [[nodiscard]] constexpr auto empty() const noexcept -> bool {
324 return s.empty();
325 }
326
328 [[nodiscard]] constexpr auto first(size_type count) -> std::span<T> {
329 return s.first(count);
330 }
331
333 [[nodiscard]] constexpr auto first(size_type count) const
334 -> std::span<T const> {
335 return std::span<T const>(s).first(count);
336 }
337
339 [[nodiscard]] constexpr auto last(size_type count) -> std::span<T> {
340 return s.last(count);
341 }
342
344 [[nodiscard]] constexpr auto last(size_type count) const
345 -> std::span<T const> {
346 return std::span<T const>(s).last(count);
347 }
348
350 [[nodiscard]] constexpr auto subspan(size_type offset,
351 size_type count = std::dynamic_extent)
352 -> std::span<T> {
353 return s.subspan(offset, count);
354 }
355
357 [[nodiscard]] constexpr auto
358 subspan(size_type offset, size_type count = std::dynamic_extent) const
359 -> std::span<T const> {
360 return std::span<T const>(s).subspan(offset, count);
361 }
362
363 // End of span member equivalents.
364
365 // We do not prevent access to storage of owning instance, but the value
366 // inside the move_only_any will not be accessible because owning_storage
367 // is a private type.
368
376 template <typename S>
377 [[nodiscard]] auto check_storage_type() const noexcept -> bool {
378 return store.type() == typeid(S);
379 }
380
391 template <typename S> [[nodiscard]] auto storage() const -> S const & {
392 return internal::move_only_any_cast<S const &>(store);
393 }
394
410 template <typename S> [[nodiscard]] auto extract_storage() -> S {
411 s = {};
412 S ret = internal::move_only_any_cast<S>(std::move(store));
413 store = {};
414 return ret;
415 }
416
427 void shrink(std::size_t start, std::size_t count = std::dynamic_extent) {
428 s = s.subspan(start, count);
429 }
430
431 // In contrast to span, bucket equality is deep equality.
432
438 friend constexpr auto operator==(bucket const &lhs, bucket const &rhs)
439 -> bool {
440 return lhs.s.size() == rhs.s.size() &&
441 std::equal(lhs.s.begin(), lhs.s.end(), rhs.s.begin());
442 }
443
445 friend auto operator<<(std::ostream &stream, bucket const &bkt)
446 -> std::ostream & {
447 static constexpr std::size_t num_to_print = 10;
448 auto const size = bkt.s.size();
449 stream << "bucket(size=" << size;
450 if constexpr (std::is_same_v<std::remove_cv_t<T>, std::byte>) {
451 for (std::size_t i = 0; i < std::min(size, num_to_print - 1); ++i)
452 stream << ", " << std::to_integer<int>(bkt.s[i]);
453 if (size > num_to_print)
454 stream << ", ...";
455 if (size >= num_to_print)
456 stream << ", " << std::to_integer<int>(bkt.s[size - 1]);
457 } else {
458 for (std::size_t i = 0; i < std::min(size, num_to_print - 1); ++i)
459 stream << ", " << bkt.s[i];
460 if (size > num_to_print)
461 stream << ", ...";
462 if (size >= num_to_print)
463 stream << ", " << bkt.s[size - 1];
464 }
465 return stream << ')';
466 }
467};
468
487template <typename T>
488[[nodiscard]] auto ad_hoc_bucket(std::span<T> s) -> bucket<T> {
489 struct ad_hoc_storage {};
490 return bucket<T>(s, ad_hoc_storage{});
491}
492
504template <typename T> struct bucket_source {
505 virtual ~bucket_source() = default;
506
516 virtual auto bucket_of_size(std::size_t size) -> bucket<T> = 0;
517
527 [[nodiscard]] virtual auto supports_shared_views() const noexcept -> bool {
528 return false;
529 }
530
564 [[nodiscard]] virtual auto
565 shared_view_of([[maybe_unused]] bucket<T> const &bkt) -> bucket<T const> {
566 throw std::logic_error(
567 "this bucket source does not support shared views");
568 }
569};
570
586template <typename T>
587class new_delete_bucket_source final : public bucket_source<T> {
588 new_delete_bucket_source() = default;
589
590 public:
592 static auto create() -> std::shared_ptr<bucket_source<T>> {
593 static std::shared_ptr<bucket_source<T>> instance(
594 new new_delete_bucket_source());
595 return instance;
596 }
597
599 auto bucket_of_size(std::size_t size) -> bucket<T> override {
600 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
601 std::unique_ptr<T[]> p(new T[size]);
602 return bucket<T>{std::span(p.get(), size), std::move(p)};
603 }
604};
605
622template <typename T>
623class sharable_new_delete_bucket_source final : public bucket_source<T> {
624 sharable_new_delete_bucket_source() = default;
625
626 public:
628 static auto create() -> std::shared_ptr<bucket_source<T>> {
629 static std::shared_ptr<bucket_source<T>> instance(
630 new sharable_new_delete_bucket_source());
631 return instance;
632 }
633
635 auto bucket_of_size(std::size_t size) -> bucket<T> override {
636 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
637 std::shared_ptr<T[]> p(new T[size]);
638 return bucket<T>{std::span(p.get(), size), std::move(p)};
639 }
640
642 [[nodiscard]] auto supports_shared_views() const noexcept
643 -> bool override {
644 return true;
645 }
646
648 [[nodiscard]] auto shared_view_of(bucket<T> const &bkt)
649 -> bucket<T const> override {
650 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
651 auto storage = bkt.template storage<std::shared_ptr<T[]>>();
652 return bucket<T const>{std::span<T const>(bkt), std::move(storage)};
653 }
654};
655
679template <typename T, bool Blocking = false, bool ClearRecycled = false>
680class recycling_bucket_source final
681 : public bucket_source<T>,
682 public std::enable_shared_from_this<
683 recycling_bucket_source<T, Blocking, ClearRecycled>> {
684 std::mutex mutex;
685 std::condition_variable not_empty_condition;
686 std::size_t max_buckets;
687 std::size_t max_recycled;
688 std::size_t bucket_count = 0;
689 std::vector<std::unique_ptr<std::vector<T>>> recyclable;
690
691 struct bucket_storage {
692 std::shared_ptr<recycling_bucket_source> source;
693 std::unique_ptr<std::vector<T>> storage;
694
695 ~bucket_storage() {
696 if (not source)
697 return;
698
699 assert(storage);
700
701 // If "large" bucket, release the underlying storage (but do go on
702 // to "recycle", so that a thread waiting on bucket_of_size() will
703 // get a bucket).
704 if (source->max_recycled > 0 &&
705 storage->size() > source->max_recycled)
706 *storage = std::vector<T>();
707
708 if constexpr (ClearRecycled)
709 storage->clear();
710
711 {
712 auto const lock = std::lock_guard(source->mutex);
713 source->recyclable.push_back(std::move(storage));
714 }
715
716 if constexpr (Blocking) {
717 // Is it safe to wake up the source when this bucket_storage
718 // might be the last thing holding on to it? Yes, because if
719 // that is the case there is no thread waiting on the source.
720 source->not_empty_condition.notify_one();
721 }
722 }
723
724 explicit bucket_storage(
725 std::shared_ptr<recycling_bucket_source> source,
726 std::unique_ptr<std::vector<T>> &&storage)
727 : source(std::move(source)), storage(std::move(storage)) {}
728
729 bucket_storage(bucket_storage const &) = delete;
730 auto operator=(bucket_storage const &) = delete;
731
732 bucket_storage(bucket_storage &&) noexcept = default;
733 auto operator=(bucket_storage &&) noexcept
734 -> bucket_storage & = default;
735 };
736
737 explicit recycling_bucket_source(
738 arg::max_bucket_count<> max_bucket_count,
739 arg::max_recycled_size<> max_recycled_size)
740 : max_buckets(max_bucket_count.value),
741 max_recycled(max_recycled_size.value) {}
742
743 public:
753 static auto create(
754 arg::max_bucket_count<> max_bucket_count =
755 arg::max_bucket_count{std::numeric_limits<std::size_t>::max()},
757 0}) -> std::shared_ptr<bucket_source<T>> {
758 return std::shared_ptr<recycling_bucket_source>(
759 new recycling_bucket_source(max_bucket_count, max_recycled_size));
760 }
761
772 auto bucket_of_size(std::size_t size) -> bucket<T> override {
773 std::unique_ptr<std::vector<T>> p;
774 {
775 auto lock = std::unique_lock(mutex);
776 if (recyclable.empty() && bucket_count < max_buckets) {
777 ++bucket_count;
778 } else {
779 if constexpr (Blocking) {
780 not_empty_condition.wait(
781 lock, [&] { return not recyclable.empty(); });
782 } else if (recyclable.empty()) {
784 "recycling bucket source exhausted");
785 }
786 p = std::move(recyclable.back());
787 recyclable.pop_back();
788 }
789 }
790 if (not p)
791 p = std::make_unique<std::vector<T>>();
792 p->resize(size);
793 auto const spn = std::span(p->data(), p->size());
794 return bucket<T>{
795 spn, bucket_storage(this->shared_from_this(), std::move(p))};
796 }
797};
798
809template <typename T, bool Blocking = false, bool ClearRecycled = false>
810class sharable_recycling_bucket_source final
811 : public bucket_source<T>,
812 public std::enable_shared_from_this<
813 sharable_recycling_bucket_source<T, Blocking, ClearRecycled>> {
814 std::mutex mutex;
815 std::condition_variable not_empty_condition;
816 std::size_t max_buckets;
817 std::size_t max_recycled;
818 std::size_t bucket_count = 0;
819 std::vector<std::unique_ptr<std::vector<T>>> recyclable;
820
821 // Wrap storage in private type to forbid observation/extraction.
822 struct bucket_storage {
823 std::shared_ptr<std::vector<T>> storage; // With custom deleter.
824 };
825
826 explicit sharable_recycling_bucket_source(
827 arg::max_bucket_count<> max_bucket_count,
828 arg::max_recycled_size<> max_recycled_size)
829 : max_buckets(max_bucket_count.value),
830 max_recycled(max_recycled_size.value) {}
831
832 public:
838 static auto create(
839 arg::max_bucket_count<> max_bucket_count =
840 arg::max_bucket_count{std::numeric_limits<std::size_t>::max()},
842 0}) -> std::shared_ptr<bucket_source<T>> {
843 return std::shared_ptr<sharable_recycling_bucket_source>(
844 new sharable_recycling_bucket_source(max_bucket_count,
845 max_recycled_size));
846 }
847
853 auto bucket_of_size(std::size_t size) -> bucket<T> override {
854 std::unique_ptr<std::vector<T>> p;
855 {
856 auto lock = std::unique_lock(mutex);
857 if (recyclable.empty() && bucket_count < max_buckets) {
858 ++bucket_count;
859 } else {
860 if constexpr (Blocking) {
861 not_empty_condition.wait(
862 lock, [&] { return not recyclable.empty(); });
863 } else if (recyclable.empty()) {
865 "sharable recycling bucket source exhausted");
866 }
867 p = std::move(recyclable.back());
868 recyclable.pop_back();
869 }
870 }
871 if (not p)
872 p = std::make_unique<std::vector<T>>();
873 p->resize(size);
874 auto const spn = std::span(*p);
875 std::shared_ptr<std::vector<T>> shptr{
876 p.release(),
877 [self = this->shared_from_this()](std::vector<T> *pv) {
878 if (not pv)
879 return;
880 if (self->max_recycled > 0 && pv->size() > self->max_recycled)
881 *pv = std::vector<T>();
882 if constexpr (ClearRecycled)
883 pv->clear();
884 {
885 auto const lock = std::lock_guard(self->mutex);
886 self->recyclable.emplace_back(pv);
887 }
888 if constexpr (Blocking)
889 self->not_empty_condition.notify_one();
890 }
891
892 };
893 return bucket<T>{spn, bucket_storage{shptr}};
894 }
895
897 [[nodiscard]] auto supports_shared_views() const noexcept
898 -> bool override {
899 return true;
900 }
901
903 [[nodiscard]] auto shared_view_of(bucket<T> const &bkt)
904 -> bucket<T const> override {
905 auto storage = bkt.template storage<bucket_storage>();
906 return bucket<T const>{std::span<T const>(bkt), std::move(storage)};
907 }
908};
909
910namespace internal {
911
912template <typename Event, typename Downstream> class extract_bucket {
913 static_assert(
914 processor<Downstream, decltype(std::declval<Event>().data_bucket)>);
915
916 Downstream downstream;
917
918 public:
919 explicit extract_bucket(Downstream downstream)
920 : downstream(std::move(downstream)) {}
921
922 [[nodiscard]] auto introspect_node() const -> processor_info {
923 return processor_info(this, "extract_bucket");
924 }
925
926 [[nodiscard]] auto introspect_graph() const -> processor_graph {
927 return downstream.introspect_graph().push_entry_point(this);
928 }
929
930 void handle(Event const &event) { downstream.handle(event.data_bucket); }
931
932 void handle(Event &&event) {
933 downstream.handle(std::move(event).data_bucket);
934 }
935
936 void flush() { downstream.flush(); }
937};
938
939} // namespace internal
940
959template <typename Event, typename Downstream>
960auto extract_bucket(Downstream downstream) {
961 return internal::extract_bucket<Event, Downstream>(std::move(downstream));
962}
963
964} // namespace tcspc
Value-semantic container for array data allowing use of custom storage.
Definition bucket.hpp:110
constexpr auto end() noexcept -> iterator
Return an iterator to the end.
Definition bucket.hpp:215
constexpr auto rend() noexcept -> reverse_iterator
Return a reverse iterator to the end.
Definition bucket.hpp:245
constexpr auto rbegin() noexcept -> reverse_iterator
Return a reverse iterator to the beginning.
Definition bucket.hpp:228
constexpr auto operator[](size_type idx) -> reference
Return an element without bounds checking.
Definition bucket.hpp:278
auto storage() const -> S const &
Observe the underlying storage.
Definition bucket.hpp:391
std::span< T const >::reverse_iterator const_reverse_iterator
Const reverse iterator type.
Definition bucket.hpp:197
std::span< T >::difference_type difference_type
Difference type.
Definition bucket.hpp:181
constexpr auto crbegin() const noexcept -> const_reverse_iterator
Return a reverse iterator to the beginning.
Definition bucket.hpp:233
std::span< T const >::iterator const_iterator
Const iterator type.
Definition bucket.hpp:193
std::span< T >::pointer pointer
Element pointer type.
Definition bucket.hpp:183
constexpr auto empty() const noexcept -> bool
Return whether this bucket is empty.
Definition bucket.hpp:323
constexpr auto at(size_type pos) const -> const_reference
Return an element with bounds checking.
Definition bucket.hpp:296
constexpr auto rbegin() const noexcept -> const_reverse_iterator
Return a reverse iterator to the beginning.
Definition bucket.hpp:239
friend constexpr auto operator==(bucket const &lhs, bucket const &rhs) -> bool
Equality comparison operator.
Definition bucket.hpp:438
constexpr auto rend() const noexcept -> const_reverse_iterator
Return a reverse iterator to the end.
Definition bucket.hpp:256
constexpr auto operator[](size_type idx) const -> const_reference
Return an element without bounds checking.
Definition bucket.hpp:283
std::span< T >::reference reference
Element reference type.
Definition bucket.hpp:187
constexpr auto subspan(size_type offset, size_type count=std::dynamic_extent) const -> std::span< T const >
Return the span of the given range of elements.
Definition bucket.hpp:358
constexpr auto at(size_type pos) -> reference
Return an element with bounds checking.
Definition bucket.hpp:289
constexpr auto last(size_type count) -> std::span< T >
Return the span of the last count elements.
Definition bucket.hpp:339
bucket(bucket &&other) noexcept=default
Move constructor.
constexpr auto back() const -> const_reference
Return the last element.
Definition bucket.hpp:273
constexpr auto front() const -> const_reference
Return the first element.
Definition bucket.hpp:265
auto operator=(bucket &&other) noexcept -> bucket &=default
Move assignment operator.
auto operator=(bucket const &other) -> bucket &
Copy assignment operator (allocates new private storage).
Definition bucket.hpp:161
std::span< T >::value_type value_type
Value type.
Definition bucket.hpp:177
std::span< T >::element_type element_type
Element type.
Definition bucket.hpp:175
constexpr auto end() const noexcept -> const_iterator
Return an iterator to the end.
Definition bucket.hpp:223
constexpr auto begin() const noexcept -> const_iterator
Return an iterator to the beginning.
Definition bucket.hpp:210
constexpr auto cend() const noexcept -> const_iterator
Return an iterator to the end.
Definition bucket.hpp:218
bucket(bucket const &other)
Copy constructor (allocates new private storage).
Definition bucket.hpp:143
constexpr auto data() noexcept -> pointer
Return the address of the data.
Definition bucket.hpp:303
constexpr auto back() -> reference
Return the last element.
Definition bucket.hpp:270
std::span< T >::reverse_iterator reverse_iterator
Reverse iterator type.
Definition bucket.hpp:195
std::span< T >::size_type size_type
Size type.
Definition bucket.hpp:179
auto extract_storage() -> S
Extract the underlying storage.
Definition bucket.hpp:410
std::span< T >::const_pointer const_pointer
Element const pointer type.
Definition bucket.hpp:185
std::span< T >::iterator iterator
Iterator type.
Definition bucket.hpp:191
void shrink(std::size_t start, std::size_t count=std::dynamic_extent)
Shrink the span of the bucket data.
Definition bucket.hpp:427
bucket() noexcept=default
Construct an empty bucket.
constexpr auto size() const noexcept -> size_type
Return the number of data elements in this bucket.
Definition bucket.hpp:313
constexpr auto last(size_type count) const -> std::span< T const >
Return the span of the last count elements.
Definition bucket.hpp:344
constexpr auto begin() noexcept -> iterator
Return an iterator to the beginning.
Definition bucket.hpp:200
std::span< T >::const_reference const_reference
Element const reference type.
Definition bucket.hpp:189
auto check_storage_type() const noexcept -> bool
Check if the underlying storage is of a given type.
Definition bucket.hpp:377
constexpr auto crend() const noexcept -> const_reverse_iterator
Return a reverse iterator to the end.
Definition bucket.hpp:250
constexpr auto front() -> reference
Return the first element.
Definition bucket.hpp:262
constexpr auto subspan(size_type offset, size_type count=std::dynamic_extent) -> std::span< T >
Return the span of the given range of elements.
Definition bucket.hpp:350
constexpr auto data() const noexcept -> const_pointer
Return the address of the data.
Definition bucket.hpp:308
constexpr auto cbegin() const noexcept -> const_iterator
Return an iterator to the beginning.
Definition bucket.hpp:205
friend auto operator<<(std::ostream &stream, bucket const &bkt) -> std::ostream &
Stream insertion operator.
Definition bucket.hpp:445
constexpr auto first(size_type count) const -> std::span< T const >
Return the span of the first count elements.
Definition bucket.hpp:333
constexpr auto first(size_type count) -> std::span< T >
Return the span of the first count elements.
Definition bucket.hpp:328
constexpr auto size_bytes() const noexcept -> size_type
Return the size of this bucket's data in bytes.
Definition bucket.hpp:318
Error thrown when buffer capacity has been exhausted.
Definition errors.hpp:84
static auto create() -> std::shared_ptr< bucket_source< T > >
Create an instance.
Definition bucket.hpp:592
auto bucket_of_size(std::size_t size) -> bucket< T > override
Implements bucket source requirement.
Definition bucket.hpp:599
auto bucket_of_size(std::size_t size) -> bucket< T > override
Implements bucket source requirement.
Definition bucket.hpp:772
static auto create(arg::max_bucket_count<> max_bucket_count=arg::max_bucket_count{std::numeric_limits< std::size_t >::max()}, arg::max_recycled_size<> max_recycled_size=arg::max_recycled_size<>{ 0}) -> std::shared_ptr< bucket_source< T > >
Create an instance.
Definition bucket.hpp:753
auto bucket_of_size(std::size_t size) -> bucket< T > override
Implements bucket source requirement.
Definition bucket.hpp:635
auto supports_shared_views() const noexcept -> bool override
Implements sharable bucket source requirement.
Definition bucket.hpp:642
static auto create() -> std::shared_ptr< bucket_source< T > >
Create an instance.
Definition bucket.hpp:628
auto shared_view_of(bucket< T > const &bkt) -> bucket< T const > override
Implements sharable bucket source requirement.
Definition bucket.hpp:648
auto supports_shared_views() const noexcept -> bool override
Implements sharable bucket source requirement.
Definition bucket.hpp:897
auto shared_view_of(bucket< T > const &bkt) -> bucket< T const > override
Implements sharable bucket source requirement.
Definition bucket.hpp:903
auto bucket_of_size(std::size_t size) -> bucket< T > override
Implements bucket source requirement.
Definition bucket.hpp:853
static auto create(arg::max_bucket_count<> max_bucket_count=arg::max_bucket_count{std::numeric_limits< std::size_t >::max()}, arg::max_recycled_size<> max_recycled_size=arg::max_recycled_size<>{ 0}) -> std::shared_ptr< bucket_source< T > >
Create an instance.
Definition bucket.hpp:838
auto ad_hoc_bucket(std::span< T > s) -> bucket< T >
Create a tcspc::bucket referencing a span.
Definition bucket.hpp:488
auto extract_bucket(Downstream downstream)
Create a processor that extracts the bucket carried by an event.
Definition bucket.hpp:960
auto count(access_tracker< count_accessor > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:312
libtcspc namespace.
Definition acquire.hpp:30
Function argument wrapper for maximum bucket count.
Definition arg_wrappers.hpp:227
T value
The argument value.
Definition arg_wrappers.hpp:229
Function argument wrapper for maximum recycled size.
Definition arg_wrappers.hpp:297
T value
The argument value.
Definition arg_wrappers.hpp:299
Abstract base class for polymorphic bucket sources.
Definition bucket.hpp:504
virtual auto bucket_of_size(std::size_t size) -> bucket< T >=0
Create a bucket of size elements of type T.
virtual auto shared_view_of(bucket< T > const &bkt) -> bucket< T const >
Create a shared view bucket that is a read-only view of the given bucket but may outlive the original...
Definition bucket.hpp:565
virtual auto supports_shared_views() const noexcept -> bool
Return whether this bucket source is a sharable bucket source.
Definition bucket.hpp:527