Wayverb
member.h
1 #pragma once
2 
3 #include "utilities/event.h"
4 #include "utilities/for_each.h"
5 #include "utilities/map.h"
6 #include "utilities/mapping_iterator_adapter.h"
7 
8 #include "cereal/types/tuple.hpp"
9 
10 #include <tuple>
11 
12 namespace wayverb {
13 namespace combined {
14 namespace model {
15 
16 template <typename Derived>
17 class basic_member {
18 public:
19  using derived_type = Derived;
21 
22  basic_member() = default;
23 
28  basic_member& operator=(const basic_member&) { return *this; }
29 
31  using connection = typename on_change::connection;
32  using scoped_connection = typename on_change::scoped_connection;
33  using callback_type = typename on_change::callback_type;
34 
35  connection connect(callback_type t) {
36  return on_change_.connect(std::move(t));
37  }
38 
39  void notify() { on_change_(*static_cast<Derived*>(this)); }
40  size_t connections() const { return on_change_.size(); }
41 
42 protected:
43  ~basic_member() noexcept = default;
44 
45 private:
46  on_change on_change_;
47 };
48 
49 #define NOTIFYING_COPY_ASSIGN_DECLARATION(TYPE) \
50  inline TYPE& operator=(const TYPE& other) { \
51  auto copy{other}; \
52  base_type::operator=(copy); \
53  this->swap(copy); \
54  this->notify(); \
55  return *this; \
56  }
57 
59 
60 template <typename Item>
61 class persistent_connection final {
62 public:
63  using scoped_connection = typename Item::scoped_connection;
64 
65  using item_t = Item;
66 
74 
76  template <typename Owner>
77  explicit persistent_connection(Owner& owner)
78  : persistent_connection{owner, item_t{}} {}
79 
80  template <typename Owner>
81  persistent_connection(Owner& owner, const item_t& i)
82  : item_{std::make_shared<item_t>(i)}
83  , connection_{
84  item_->connect([o = &owner](auto&) { o->notify(); })} {}
85 
87  persistent_connection(persistent_connection&&) noexcept = default;
88 
89  persistent_connection& operator=(const persistent_connection&) = delete;
90  persistent_connection& operator=(persistent_connection&&) noexcept =
91  default;
92 
98  const std::shared_ptr<item_t>& item() const { return item_; }
99 
100  auto get() const { return item_.get(); }
101  auto operator-> () const { return item_.operator->(); }
102  auto& operator*() const { return item_.operator*(); }
103 
104  void block() { connection_.connection.block(); }
105  void unblock() { connection_.connection.unblock(); }
106 
107 private:
108  std::shared_ptr<item_t> item_;
109  scoped_connection connection_;
110 };
111 
112 struct item_extractor final {
113  template <typename T>
114  auto& operator()(const persistent_connection<T>& conn) const {
115  return *conn;
116  }
117 };
118 
119 template <typename It>
120 static auto make_item_extractor_iterator(It it) {
121  return util::make_mapping_iterator_adapter(std::move(it), item_extractor{});
122 }
123 
125 
126 template <typename Derived, typename... DataMembers>
127 class owning_member : public basic_member<Derived> {
128 public:
129  using derived_type = Derived;
130  using base_type = owning_member<Derived, DataMembers...>;
131 
135  : data_members_{persistent_connection<DataMembers>{
136  *static_cast<Derived*>(this)}...} {}
137 
140  explicit owning_member(const DataMembers&... data_members)
141  : data_members_{persistent_connection<DataMembers>{
142  *static_cast<Derived*>(this), data_members}...} {}
143 
147  : owning_member{
148  other,
149  std::make_index_sequence<sizeof...(DataMembers)>{}} {}
150 
155  assign(other, std::make_index_sequence<sizeof...(DataMembers)>{});
156  return *this;
157  }
158 
159  template <typename Archive>
160  void serialize(Archive& archive) {
163  util::for_each(
164  [&archive](const auto& i) { archive(item_extractor{}(i)); },
165  data_members_);
166  }
167 
168  // Implemented as member functions because they need to poke at private
169  // data members.
170  bool operator==(const owning_member& other) const {
171  return tie() == other.tie();
172  }
173 
174  bool operator!=(const owning_member& other) const {
175  return !operator==(other);
176  }
177 
178 protected:
179  ~owning_member() = default;
180 
181  template <size_t I>
182  const auto& get() const & {
183  return std::get<I>(data_members_);
184  }
185 
186  template <size_t I>
187  auto& get() & {
188  return std::get<I>(data_members_);
189  }
190 
191  template <typename T>
192  const auto& get() const & {
193  return std::get<persistent_connection<T>>(data_members_);
194  }
195 
196  template <typename T>
197  auto& get() & {
198  return std::get<persistent_connection<T>>(data_members_);
199  }
200 
201 private:
202  using data_members = std::tuple<persistent_connection<DataMembers>...>;
203 
204  template <size_t I>
205  using tuple_element_t = std::tuple_element_t<I, data_members>;
206 
207  template <size_t... Ix>
208  owning_member(const owning_member& other, std::index_sequence<Ix...>)
209  : data_members_{tuple_element_t<Ix>{
210  *static_cast<Derived*>(this),
211  item_extractor{}(std::get<Ix>(other.data_members_))}...} {
212  }
213 
214  template <size_t... Ix>
215  void assign(const owning_member& other, std::index_sequence<Ix...>) {
216  (void)std::initializer_list<int>{
217  ((void)(item_extractor{}(std::get<Ix>(data_members_)) =
218  item_extractor{}(
219  std::get<Ix>(other.data_members_))),
220  0)...};
221  }
222 
223  template <size_t... Ix>
224  auto tie(std::index_sequence<Ix...>) const {
225  return std::tie(item_extractor{}(std::get<Ix>(data_members_))...);
226  }
227 
228  auto tie() const {
229  return tie(std::make_index_sequence<sizeof...(DataMembers)>{});
230  }
231 
232  data_members data_members_;
233 };
234 
235 } // namespace model
236 } // namespace combined
237 } // namespace wayverb
basic_member(const basic_member &)
Definition: member.h:27
owning_member(const DataMembers &...data_members)
Definition: member.h:140
persistent_connection(Owner &owner)
Assumption: owner will always outlive the connection.
Definition: member.h:77
owning_member()
Definition: member.h:134
void serialize(Archive &archive)
Definition: member.h:160
const std::shared_ptr< item_t > & item() const
Definition: member.h:98
Definition: capsule_base.h:9
owning_member(const owning_member &other)
Definition: member.h:146
owning_member & operator=(const owning_member &other)
Definition: member.h:154