Skip to content

Commit 6c6f868

Browse files
authored
Merge pull request #208 from TheCoconutChef/enable-reader-fwd-decl
allow forward declaration of values held by reader
2 parents 503ea6a + 7dbde7f commit 6c6f868

File tree

3 files changed

+86
-33
lines changed

3 files changed

+86
-33
lines changed

lager/detail/nodes.hpp

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -128,26 +128,19 @@ struct notifying_guard_t
128128
};
129129

130130
/*!
131-
* Base class for the various node types. Provides basic
132-
* functionality for setting values and propagating them to children.
131+
* Interface for nodes capable of notifying observers.
133132
*/
134133
template <typename T>
135-
class reader_node : public reader_node_base
134+
class observable_reader_node
136135
{
137136
public:
138137
using value_type = T;
139138
using signal_type = signal<const value_type&>;
140139

141-
reader_node(T value)
142-
: current_(std::move(value))
143-
, last_(current_)
144-
{}
145-
146-
virtual void recompute() = 0;
147-
virtual void refresh() = 0;
140+
virtual void refresh() = 0;
148141

149-
const value_type& current() const { return current_; }
150-
const value_type& last() const { return last_; }
142+
const value_type& current() const { return *current_view_; }
143+
const value_type& last() const { return *last_view_; }
151144

152145
void link(std::weak_ptr<reader_node_base> child)
153146
{
@@ -159,6 +152,56 @@ class reader_node : public reader_node_base
159152
"Child node must not be linked twice");
160153
children_.push_back(child);
161154
}
155+
auto observers() -> signal_type& { return observers_; }
156+
157+
protected:
158+
observable_reader_node(const T* current, const T* last)
159+
: current_view_(current)
160+
, last_view_(last)
161+
{
162+
}
163+
164+
void collect()
165+
{
166+
using namespace std;
167+
children_.erase(remove_if(begin(children_),
168+
end(children_),
169+
mem_fn(&weak_ptr<reader_node_base>::expired)),
170+
end(children_));
171+
}
172+
173+
const std::vector<std::weak_ptr<reader_node_base>>& children() const
174+
{
175+
return children_;
176+
}
177+
178+
private:
179+
const T* current_view_;
180+
const T* last_view_;
181+
signal_type observers_;
182+
std::vector<std::weak_ptr<reader_node_base>> children_;
183+
};
184+
/*!
185+
* Base class for the various node types. Provides basic
186+
* functionality for setting values and propagating them to children.
187+
*/
188+
template <typename T>
189+
class reader_node
190+
: public reader_node_base
191+
, public observable_reader_node<T>
192+
{
193+
public:
194+
using value_type = typename observable_reader_node<T>::value_type;
195+
using signal_type = typename observable_reader_node<T>::signal_type;
196+
197+
reader_node(T value)
198+
: observable_reader_node<T>(&current_, &last_)
199+
, current_(std::move(value))
200+
, last_(current_)
201+
{
202+
}
203+
204+
virtual void recompute() = 0;
162205

163206
template <typename U>
164207
void push_down(U&& value)
@@ -171,12 +214,12 @@ class reader_node : public reader_node_base
171214

172215
void send_down() final
173216
{
174-
recompute();
217+
this->recompute();
175218
if (needs_send_down_) {
176219
last_ = current_;
177220
needs_send_down_ = false;
178221
needs_notify_ = true;
179-
for (auto& wchild : children_) {
222+
for (auto& wchild : this->children()) {
180223
if (auto child = wchild.lock()) {
181224
child->send_down();
182225
}
@@ -193,37 +236,24 @@ class reader_node : public reader_node_base
193236
notifying_guard_t notifying_guard(notifying_);
194237
bool garbage = false;
195238

196-
observers_(last_);
197-
for (size_t i = 0, size = children_.size(); i < size; ++i) {
198-
if (auto child = children_[i].lock()) {
239+
this->observers()(last_);
240+
for (auto& wchild : this->children()) {
241+
if (auto child = wchild.lock()) {
199242
child->notify();
200243
} else {
201244
garbage = true;
202245
}
203246
}
204247

205248
if (garbage && !notifying_guard.value_) {
206-
collect();
249+
this->collect();
207250
}
208251
}
209252
}
210253

211-
auto observers() -> signal_type& { return observers_; }
212-
213254
private:
214-
void collect()
215-
{
216-
using namespace std;
217-
children_.erase(remove_if(begin(children_),
218-
end(children_),
219-
mem_fn(&weak_ptr<reader_node_base>::expired)),
220-
end(children_));
221-
}
222-
223255
value_type current_;
224256
value_type last_;
225-
std::vector<std::weak_ptr<reader_node_base>> children_;
226-
signal_type observers_;
227257

228258
bool needs_send_down_ = false;
229259
bool needs_notify_ = false;

lager/reader.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ class reader_base
125125
* Provides access to reading values of type `T`.
126126
*/
127127
template <typename T>
128-
class reader : public reader_base<detail::reader_node<T>>
128+
class reader : public reader_base<detail::observable_reader_node<T>>
129129
{
130-
using base_t = reader_base<detail::reader_node<T>>;
130+
using base_t = reader_base<detail::observable_reader_node<T>>;
131131

132132
public:
133133
using base_t::base_t;

test/cursor.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,26 @@ TEST_CASE("lenses over with expression")
226226
CHECK(person_data->name == "new name");
227227
CHECK(name.get() == "new name");
228228
}
229+
230+
struct Foo;
231+
struct Bar
232+
{
233+
lager::reader<Foo> foo;
234+
reader<Foo> get_reader() const;
235+
};
236+
struct Baz
237+
{
238+
Baz(const lager::reader<Foo>& r);
239+
};
240+
TEST_CASE("forward declare a reader value")
241+
{
242+
auto bar = Bar();
243+
auto baz = Baz(bar.get_reader());
244+
}
245+
struct Foo
246+
{};
247+
lager::reader<Foo> Bar::get_reader() const
248+
{
249+
return lager::make_constant(Foo());
250+
}
251+
Baz::Baz(const lager::reader<Foo>&) {}

0 commit comments

Comments
 (0)