1
/** \file incremental_expression.h */ // -*-c++-*-
3
// Copyright (C) 2009-2010 Daniel Burrows
5
// This program is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU General Public License as
7
// published by the Free Software Foundation; either version 2 of
8
// the License, or (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; see the file COPYING. If not, write to
17
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
// Boston, MA 02111-1307, USA.
21
#ifndef BOOL_EXPRESSION_H
22
#define BOOL_EXPRESSION_H
24
#include <cwidget/generic/util/eassert.h>
25
#include <cwidget/generic/util/ref_ptr.h>
27
#include <generic/util/compare3.h>
28
#include <generic/util/refcounted_base.h>
35
// A system of incrementally computed expressions stored as a DAG.
36
// NOT THREADSAFE (the weak-reference system would utterly break in
37
// the presence of threads without a lot of expensive locking, and
38
// inside the resolver we don't need it).
40
// \todo Support delayed propagation of updates? (basically using a
41
// queue -- this would avoid excessive recursion, and also avoid
42
// having an unresponsive UI if there's a lot of stuff to update)
43
// Maybe have a propagate() method on a generic (non-templated) base
44
// class and have the user pass in a deque of pointers to that class
45
// when signaling updates or modifying variable values. propagate()
46
// would also accept a deque, to totally flatten out the computation.
52
class expression_weak_ref;
54
// Generic base class so arbitrary incoming weak references can be
55
// invalidated by the expression type.
56
class expression_weak_ref_generic
58
// This should be a friend of the weak_ref below, but I don't
59
// remember how to make friends and templates get along; making its
60
// private parts protected instead.
64
expression_weak_ref_generic(bool _valid)
70
expression_weak_ref_generic()
75
bool get_valid() const
80
// This should be private, but it has to be exposed to a templated
81
// class (expression<T>).
88
/** \brief A weak reference to something derived from "expression".
90
* \tparam T The type that is encapsulated (should inherit from "expression").
93
class expression_weak_ref : public expression_weak_ref_generic
103
expression_weak_ref(T *_expr);
104
expression_weak_ref(const cwidget::util::ref_ptr<T> &_expr);
106
expression_weak_ref(const expression_weak_ref &other);
108
expression_weak_ref &operator=(const expression_weak_ref &other);
117
bool operator==(const expression_weak_ref &other) const
119
return expr == other.expr;
122
bool operator==(const T *other) const
124
return expr == other;
127
int compare(const expression_weak_ref &other) const
129
return aptitude::util::compare3(expr, other.expr);
132
bool operator<(const expression_weak_ref &other) const
134
return expr < other.expr;
137
~expression_weak_ref();
145
class compare3_f<expression_weak_ref<T> >
148
int operator()(const expression_weak_ref<T> &r1,
149
const expression_weak_ref<T> &r2) const
151
return r1.compare(r2);
158
class expression_container;
160
/** \brief An expression whose value can be computed incrementally
161
* and updated in its parents.
163
* \typeparam T The type of value computed by this expression;
164
* should be copy-constructable and equality-comparable.
167
class expression : public aptitude::util::refcounted_base_not_threadsafe
169
// Weak references to parents.
170
std::set<expression_weak_ref<expression_container<T> > > parents;
172
// Incoming weak references.
173
std::set<expression_weak_ref_generic *> weak_refs;
175
// These two routines should be private, but they need to be exposed
176
// to a templated class (expression_weak_ref<T>).
178
void add_weak_ref(expression_weak_ref_generic *ref)
180
weak_refs.insert(ref);
183
void remove_weak_ref(expression_weak_ref_generic *ref)
185
weak_refs.erase(ref);
189
void signal_value_changed(T old_value, T new_value)
191
cwidget::util::ref_ptr<expression> self(this);
193
// Strip out dead references as we go, to save a bit of space.
194
typename std::set<expression_weak_ref<expression_container<T> > >::iterator
195
curr = parents.begin();
197
while(curr != parents.end())
199
typename std::set<expression_weak_ref<expression_container<T> > >::iterator
203
if(curr->get_valid())
204
curr->get_value()->child_modified(self, old_value, new_value);
213
virtual ~expression()
215
for(typename std::set<expression_weak_ref_generic *>::const_iterator it =
216
weak_refs.begin(); it != weak_refs.end(); ++it)
219
weak_refs.clear(); // Not strictly necessary, but avoids potential
223
// Add a weak reference to the given expression; its
224
// child_modified() routine will be invoked when this child's value
226
void add_parent(expression_container<T> *parent)
229
parents.insert(parent);
233
class parent_equals_weak_ref
235
const expression_container<T> *parent;
238
parent_equals_weak_ref(const expression_container<T> *_parent)
243
bool operator()(const expression_weak_ref<expression_container<T> > &other) const
245
return other == parent;
250
void remove_parent(expression_container<T> *parent)
252
parents.erase(expression_weak_ref<expression_container<T> >(parent));
255
virtual T get_value() = 0;
256
virtual void dump(std::ostream &out) = 0;
259
/** \brief Base class for expressions that can contain other
260
* expressions as children.
263
class expression_container : public expression<T>
266
/** \brief Invoked when the value of a child has changed from
267
* old_value to new_value.
269
* When this method is called, the value really has changed (i.e.,
270
* old_value does not equal new_value).
272
virtual void child_modified(const cwidget::util::ref_ptr<expression<T> > &child,
277
/** \brief Base class for objects that have a single sub-expression. */
279
class expression_box : public expression_container<T>
281
cwidget::util::ref_ptr<expression<T> > child;
284
expression_box() : child() { }
286
expression_box(const cwidget::util::ref_ptr<expression<T> > &_child)
290
child->add_parent(this);
293
expression_box(const expression_box &other)
297
child->add_parent(this);
303
child->remove_parent(this);
306
void set_child(const cwidget::util::ref_ptr<expression<T> > &new_child)
309
child->remove_parent(this);
311
if(new_child.valid())
312
new_child->add_parent(this);
315
/** \brief Set the child of this box to the child of the other box.
317
expression_box &operator=(const expression_box &other)
319
set_child(other.child);
323
const cwidget::util::ref_ptr<expression<T> > &get_child() const
328
/** \brief Returns the child's value, or a default-constructed T if
334
return child->get_value();
339
/** \brief Write this expression to the given stream.
341
* The default implementation writes nothing if the child is
342
* invalid, and writes the child if the child is valid.
344
void dump(std::ostream &out)
346
if(get_child().valid())
347
get_child()->dump(out);
351
/** \brief Base class for expressions that trivially wrap their
355
class expression_wrapper : public expression_box<T>
358
expression_wrapper() : expression_box<T>() { }
359
expression_wrapper(const cwidget::util::ref_ptr<expression<T> > &child)
360
: expression_box<T>(child)
363
expression_wrapper(const expression_wrapper &other)
364
: expression_box<T>(other)
368
expression_wrapper &operator=(const expression_wrapper &other)
370
set_child(other.get_child());
374
/** \brief Invoked by the default implementation of child_modified.
376
* This method's default implementation does nothing.
378
virtual void changed(T new_value)
382
void child_modified(const cwidget::util::ref_ptr<expression<T> > &child,
390
/** \brief Base class for N-ary containers that support adding and
394
class expression_container_base : public expression_container<T>
396
// Strong references to children.
397
std::vector<cwidget::util::ref_ptr<expression<T> > > children;
400
template<typename Iter>
401
expression_container_base(Iter begin, Iter end)
402
: children(begin, end)
404
for(typename std::vector<cwidget::util::ref_ptr<expression<T> > >::const_iterator
405
it = get_children().begin(); it != get_children().end(); ++it)
407
(*it)->add_parent(this);
410
const std::vector<cwidget::util::ref_ptr<expression<T> > > &get_children() const
415
/** \brief Add a new child to this container. */
416
virtual void add_child(const cwidget::util::ref_ptr<expression<T> > &new_child)
418
children.push_back(new_child);
421
/** \brief Remove one copy of a child from this container. */
422
virtual void remove_child(const cwidget::util::ref_ptr<expression<T> > &child)
425
child->remove_parent(this);
427
typename std::vector<cwidget::util::ref_ptr<expression<T> > >::iterator
428
found = std::find(children.begin(), children.end(), child);
430
if(found != children.end())
431
children.erase(found);
434
virtual std::string get_name() = 0;
436
void dump(std::ostream &out)
438
out << get_name() << "(";
439
for(typename std::vector<cwidget::util::ref_ptr<expression<T> > >::const_iterator
440
it = get_children().begin(); it != get_children().end(); ++it)
442
if(it != get_children().begin())
455
expression_weak_ref<T>::expression_weak_ref(T *_expr)
456
: expression_weak_ref_generic(true), expr(_expr)
458
expr->add_weak_ref(this);
462
expression_weak_ref<T>::expression_weak_ref(const cwidget::util::ref_ptr<T> &_expr)
463
: expression_weak_ref_generic(true), expr(_expr.unsafe_get_ref())
465
expr->add_weak_ref(this);
469
expression_weak_ref<T>::expression_weak_ref(const expression_weak_ref<T> &other)
470
: expression_weak_ref_generic(other.get_valid()), expr(other.expr)
473
expr->add_weak_ref(this);
477
expression_weak_ref<T> &expression_weak_ref<T>::operator=(const expression_weak_ref<T> &other)
480
expr->remove_weak_ref(this);
486
expr->add_weak_ref(this);
492
expression_weak_ref<T>::~expression_weak_ref()
495
expr->remove_weak_ref(this);
498
/** \brief Represents a variable in the expression language.
500
* Variables can be modified arbitrarily; changes are immediately
501
* propagated to parent expressions.
503
* It would be nice if the user could attach names for better
504
* printing of expressions, but that would take a lot of memory.
507
class var_e : public expression<T>
512
var_e(T _value) : value(_value)
517
static cwidget::util::ref_ptr<var_e> create(T value)
519
return new var_e(value);
527
/** \brief Set the value of this expression to new_value,
528
* and propagate it to our parent if necessary.
530
void set_value(T new_value)
532
if(value != new_value)
536
signal_value_changed(old_value, new_value);
540
void dump(std::ostream &out)
546
/** \brief Boolean-specific expressions. */
550
// Base class for Boolean expressions that use the number of their
551
// sub-parts that are "true" to determine their own value.
552
class counting_bool_e : public expression_container_base<bool>
554
std::vector<cwidget::util::ref_ptr<expression<bool> > >::size_type num_true;
556
// Invoked from the constructor; counts how many of the children are
558
void init_num_true();
560
template<typename Iter>
561
counting_bool_e(Iter begin, Iter end)
562
: expression_container_base<bool>(begin, end), num_true(0)
567
std::vector<cwidget::util::ref_ptr<expression<bool> > >::size_type
573
void child_modified(const cwidget::util::ref_ptr<expression<bool> > &child,
577
void add_child(const cwidget::util::ref_ptr<expression<bool> > &new_child);
578
void remove_child(const cwidget::util::ref_ptr<expression<bool> > &child);
581
class and_e : public counting_bool_e
583
template<typename Iter>
584
and_e(Iter begin, Iter end)
585
: counting_bool_e(begin, end)
590
template<typename Iter>
591
static cwidget::util::ref_ptr<and_e>
592
create(Iter begin, Iter end)
594
return new and_e(begin, end);
597
static cwidget::util::ref_ptr<and_e>
598
create(const cwidget::util::ref_ptr<expression<bool> > &e1,
599
const cwidget::util::ref_ptr<expression<bool> > &e2)
601
cwidget::util::ref_ptr<expression<bool> > tmp[2];
605
return create(tmp, tmp + 2);
609
std::string get_name();
612
class or_e : public counting_bool_e
614
template<typename Iter>
615
or_e(Iter begin, Iter end)
616
: counting_bool_e(begin, end)
621
template<typename Iter>
622
static cwidget::util::ref_ptr<or_e>
623
create(Iter begin, Iter end)
625
return new or_e(begin, end);
628
static cwidget::util::ref_ptr<or_e>
629
create(const cwidget::util::ref_ptr<expression<bool> > &e1,
630
const cwidget::util::ref_ptr<expression<bool> > &e2)
632
cwidget::util::ref_ptr<expression<bool> > tmp[2];
636
return create(tmp, tmp + 2);
640
std::string get_name();
643
class not_e : public expression_box<bool>
645
not_e(const cwidget::util::ref_ptr<expression<bool> > &_child)
646
: expression_box<bool>(_child)
651
static cwidget::util::ref_ptr<not_e>
652
create(const cwidget::util::ref_ptr<expression<bool> > &child)
654
return new not_e(child);
657
void child_modified(const cwidget::util::ref_ptr<expression<bool> > &child,
661
void dump(std::ostream &out);
665
std::ostream &operator<<(std::ostream &out,
666
const cwidget::util::ref_ptr<expression<T> > &o)