9#include "arg_wrappers.hpp"
11#include "introspect.hpp"
12#include "move_only_any.hpp"
13#include "processor.hpp"
17#include <condition_variable>
111 struct owning_storage {
113 std::unique_ptr<T[]> p;
116 explicit owning_storage(std::unique_ptr<T[]> ptr)
117 : p(std::move(ptr)) {}
121 internal::move_only_any store;
136 template <typename S>
138 : s(span), store(std::forward<S>(
storage)) {}
144 : store(std::invoke([&s = other.s] {
145 using TMut = std::remove_cv_t<T>;
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));
153 T *ptr = internal::move_only_any_cast<owning_storage>(&store)->p.get();
154 s = {ptr, other.s.size()};
206 return std::span<T const>(s).begin();
215 [[nodiscard]]
constexpr auto end() noexcept ->
iterator {
return s.end(); }
219 return std::span<T const>(s).end();
233 [[nodiscard]]
constexpr auto crbegin() const noexcept
235 return std::span<T const>(s).rbegin();
239 [[nodiscard]]
constexpr auto rbegin() const noexcept
250 [[nodiscard]]
constexpr auto crend() const noexcept
252 return std::span<T const>(s).rend();
256 [[nodiscard]]
constexpr auto rend() const noexcept
266 return std::span<T const>(s).front();
274 return std::span<T const>(s).back();
291 throw std::out_of_range(
"bucket element index out of range");
298 throw std::out_of_range(
"bucket element index out of range");
319 return s.size_bytes();
323 [[nodiscard]]
constexpr auto empty() const noexcept ->
bool {
329 return s.first(
count);
334 -> std::span<T const> {
335 return std::span<T const>(s).first(
count);
340 return s.last(
count);
345 -> std::span<T const> {
346 return std::span<T const>(s).last(
count);
353 return s.subspan(offset,
count);
357 [[nodiscard]]
constexpr auto
359 -> std::span<T const> {
360 return std::span<T const>(s).subspan(offset,
count);
376 template <
typename S>
378 return store.type() ==
typeid(S);
391 template <
typename S> [[nodiscard]]
auto storage() const -> S const & {
392 return internal::move_only_any_cast<S const &>(store);
412 S ret = internal::move_only_any_cast<S>(std::move(store));
427 void shrink(std::size_t start, std::size_t
count = std::dynamic_extent) {
428 s = s.subspan(start,
count);
440 return lhs.s.size() == rhs.s.size() &&
441 std::equal(lhs.s.begin(), lhs.s.end(), rhs.s.begin());
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)
455 if (
size >= num_to_print)
456 stream <<
", " << std::to_integer<int>(bkt.s[
size - 1]);
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)
462 if (
size >= num_to_print)
463 stream <<
", " << bkt.s[
size - 1];
465 return stream <<
')';
489 struct ad_hoc_storage {};
564 [[nodiscard]]
virtual auto
566 throw std::logic_error(
567 "this bucket source does not support shared views");
588 new_delete_bucket_source() =
default;
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());
601 std::unique_ptr<T[]> p(
new T[size]);
602 return bucket<T>{std::span(p.get(), size), std::move(p)};
624 sharable_new_delete_bucket_source() =
default;
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());
637 std::shared_ptr<T[]> p(
new T[size]);
638 return bucket<T>{std::span(p.get(), size), std::move(p)};
651 auto storage = bkt.template storage<std::shared_ptr<T[]>>();
679template <
typename T,
bool Blocking = false,
bool ClearRecycled = false>
680class recycling_bucket_source final
682 public std::enable_shared_from_this<
683 recycling_bucket_source<T, Blocking, ClearRecycled>> {
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;
691 struct bucket_storage {
692 std::shared_ptr<recycling_bucket_source> source;
693 std::unique_ptr<std::vector<T>> storage;
704 if (source->max_recycled > 0 &&
705 storage->size() > source->max_recycled)
706 *storage = std::vector<T>();
708 if constexpr (ClearRecycled)
712 auto const lock = std::lock_guard(source->mutex);
713 source->recyclable.push_back(std::move(storage));
716 if constexpr (Blocking) {
720 source->not_empty_condition.notify_one();
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)) {}
729 bucket_storage(bucket_storage
const &) =
delete;
730 auto operator=(bucket_storage
const &) =
delete;
732 bucket_storage(bucket_storage &&)
noexcept =
default;
733 auto operator=(bucket_storage &&)
noexcept
734 -> bucket_storage & =
default;
737 explicit recycling_bucket_source(
740 : max_buckets(max_bucket_count.
value),
741 max_recycled(max_recycled_size.
value) {}
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));
773 std::unique_ptr<std::vector<T>> p;
775 auto lock = std::unique_lock(mutex);
776 if (recyclable.empty() && bucket_count < max_buckets) {
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");
786 p = std::move(recyclable.back());
787 recyclable.pop_back();
791 p = std::make_unique<std::vector<T>>();
793 auto const spn = std::span(p->data(), p->size());
795 spn, bucket_storage(this->shared_from_this(), std::move(p))};
809template <
typename T,
bool Blocking = false,
bool ClearRecycled = false>
810class sharable_recycling_bucket_source final
812 public std::enable_shared_from_this<
813 sharable_recycling_bucket_source<T, Blocking, ClearRecycled>> {
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;
822 struct bucket_storage {
823 std::shared_ptr<std::vector<T>> storage;
826 explicit sharable_recycling_bucket_source(
829 : max_buckets(max_bucket_count.
value),
830 max_recycled(max_recycled_size.
value) {}
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,
854 std::unique_ptr<std::vector<T>> p;
856 auto lock = std::unique_lock(mutex);
857 if (recyclable.empty() && bucket_count < max_buckets) {
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");
867 p = std::move(recyclable.back());
868 recyclable.pop_back();
872 p = std::make_unique<std::vector<T>>();
874 auto const spn = std::span(*p);
875 std::shared_ptr<std::vector<T>> shptr{
877 [self = this->shared_from_this()](std::vector<T> *pv) {
880 if (self->max_recycled > 0 && pv->size() > self->max_recycled)
881 *pv = std::vector<T>();
882 if constexpr (ClearRecycled)
885 auto const lock = std::lock_guard(self->mutex);
886 self->recyclable.emplace_back(pv);
888 if constexpr (Blocking)
889 self->not_empty_condition.notify_one();
893 return bucket<T>{spn, bucket_storage{shptr}};
905 auto storage = bkt.template storage<bucket_storage>();
912template <
typename Event,
typename Downstream>
class extract_bucket {
914 processor<Downstream, decltype(std::declval<Event>().data_bucket)>);
916 Downstream downstream;
919 explicit extract_bucket(Downstream downstream)
920 : downstream(std::move(downstream)) {}
922 [[nodiscard]]
auto introspect_node() const -> processor_info {
923 return processor_info(
this,
"extract_bucket");
926 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
927 return downstream.introspect_graph().push_entry_point(
this);
930 void handle(Event
const &event) { downstream.handle(event.data_bucket); }
932 void handle(Event &&event) {
933 downstream.handle(std::move(event).data_bucket);
936 void flush() { downstream.flush(); }
959template <
typename Event,
typename Downstream>
961 return internal::extract_bucket<Event, Downstream>(std::move(downstream));
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