ReactivePlusPlus
ReactiveX implementation for C++20
Loading...
Searching...
No Matches
container.hpp
1// ReactivePlusPlus library
2//
3// Copyright Aleksey Loginov 2023 - present.
4// Distributed under the Boost Software License, Version 1.0.
5// (See accompanying file LICENSE_1_0.txt or copy at
6// https://www.boost.org/LICENSE_1_0.txt)
7//
8// Project home: https://github.com/victimsnino/ReactivePlusPlus
9
10#pragma once
11
12#include <rpp/disposables/disposable_wrapper.hpp>
13#include <rpp/utils/exceptions.hpp>
14
15#include <algorithm>
16#include <new>
17#include <vector>
18
19namespace rpp::details::disposables
20{
21 class dynamic_disposables_container
22 {
23 public:
24 explicit dynamic_disposables_container() = default;
25
26 dynamic_disposables_container(const dynamic_disposables_container&) = delete;
27 dynamic_disposables_container(dynamic_disposables_container&& other) noexcept = default;
28
29 dynamic_disposables_container& operator=(const dynamic_disposables_container& other) = delete;
30 dynamic_disposables_container& operator=(dynamic_disposables_container&& other) noexcept = default;
31
32 void push_back(const rpp::disposable_wrapper& d)
33 {
34 m_data.push_back(d);
35 }
36
37 void push_back(rpp::disposable_wrapper&& d)
38 {
39 m_data.push_back(std::move(d));
40 }
41
42 void remove(const rpp::disposable_wrapper& d)
43 {
44 m_data.erase(std::remove(m_data.begin(), m_data.end(), d), m_data.end());
45 }
46
47 void dispose() const
48 {
49 for (const auto& d : m_data)
50 {
51 d.dispose();
52 }
53 }
54
55 void clear()
56 {
57 m_data.clear();
58 }
59
60 private:
61 mutable std::vector<rpp::disposable_wrapper> m_data{};
62 };
63
64 template<size_t Count>
65 class static_disposables_container
66 {
67 public:
68 static_disposables_container() = default;
69 static_disposables_container(const static_disposables_container&) = delete;
70 static_disposables_container& operator=(const static_disposables_container& other) = delete;
71
72 static_disposables_container& operator=(static_disposables_container&& other) noexcept
73 {
74 if (this == &other)
75 return *this;
76
77 m_size = other.m_size;
78 for (size_t i = 0; i < m_size; ++i)
79 std::construct_at(get(i), std::move(*other.get(i)));
80
81 other.clear();
82 return *this;
83 }
84
85 static_disposables_container(static_disposables_container&& other) noexcept
86 {
87 *this = std::move(other);
88 }
89
90 ~static_disposables_container() noexcept
91 {
92 clear();
93 }
94
95 void push_back(const rpp::disposable_wrapper& d)
96 {
97 if (m_size >= Count)
98 throw rpp::utils::more_disposables_than_expected{"static_disposables_container obtained more disposables than expected"};
99 std::construct_at(get(m_size++), d);
100 }
101
102 void push_back(rpp::disposable_wrapper&& d)
103 {
104 if (m_size >= Count)
105 throw rpp::utils::more_disposables_than_expected{"static_disposables_container obtained more disposables than expected"};
106 std::construct_at(get(m_size++), std::move(d));
107 }
108
109 void remove(const rpp::disposable_wrapper& d)
110 {
111 for (size_t i = 0; i < m_size;)
112 {
113 if (*get(i) != d)
114 {
115 ++i;
116 continue;
117 }
118
119 for (size_t j = i + 1; j < m_size; ++j)
120 *get(j - 1) = std::move(*get(j));
121
122 std::destroy_at(get(--m_size));
123 }
124 }
125
126 void dispose() const
127 {
128 for (size_t i = 0; i < m_size; ++i)
129 {
130 get(i)->dispose();
131 }
132 }
133
134 void clear()
135 {
136 for (size_t i = 0; i < m_size; ++i)
137 std::destroy_at(get(i));
138 m_size = 0;
139 }
140
141 private:
142 const rpp::disposable_wrapper* get(size_t i) const
143 {
144 return std::launder(reinterpret_cast<const rpp::disposable_wrapper*>(&m_data[i * sizeof(rpp::disposable_wrapper)]));
145 }
146 rpp::disposable_wrapper* get(size_t i)
147 {
148 return std::launder(reinterpret_cast<rpp::disposable_wrapper*>(&m_data[i * sizeof(rpp::disposable_wrapper)]));
149 }
150
151 private:
152 alignas(rpp::disposable_wrapper) std::byte m_data[sizeof(rpp::disposable_wrapper) * Count]{};
153 size_t m_size{};
154 };
155
156 template<>
157 class static_disposables_container<0>
158 {
159 public:
160 [[noreturn]] static void push_back(const rpp::disposable_wrapper&)
161 {
162 throw rpp::utils::more_disposables_than_expected{"static_disposables_container<0> expected no disposables but received at least one"};
163 }
164
165 static void remove(const rpp::disposable_wrapper&) { }
166 static void dispose() { }
167 static void clear() { }
168 };
169} // namespace rpp::details::disposables
disposable_wrapper_impl< interface_disposable > disposable_wrapper
Wrapper to keep "simple" disposable. Specialization of rpp::disposable_wrapper_impl.
Definition fwd.hpp:34
Definition exceptions.hpp:23