54
/** \brief A class used in metaprogramming for imm::set.
58
template<typename Val, typename AccumVal, typename AccumOps, int w>
61
/** \brief Helper function used below to accumulate information up
64
* \tparam AccumOps The class carrying information about how to
65
* accumulate values up the tree; if this is nil_t, then this
68
* \todo Isn't there a better way of getting this behavior? I
69
* tried partially specializing a private member function, but ran
70
* into syntactic trouble.
72
template<typename Val, typename AccumVal, typename AccumOps, int w>
78
const wtree_node<Val, AccumVal, AccumOps, w> &left,
79
const wtree_node<Val, AccumVal, AccumOps, w> &right,
80
const AccumOps &accumOps);
52
83
/** A generic node in a weighted tree as described in "Implementing
53
84
* Sets Efficiently In A Functional Language". The tree invariant
54
85
* is that the tree is not "too unbalanced"; in this case, that no
62
93
* The weighted-tree data structure is reasonably efficient and
63
94
* much more straightforward to implement correctly.
97
* In addition to the above notes, this class can be used to
98
* iteratively maintain the result of accumulating an associative
99
* and commutative operation across the set.
101
* \tparam Val The type of value stored in this set.
103
* \tparam AccumVal The type of value being accumulated at each
104
* node, or nil_t for no accumulation.
106
* \tparam AccumOps If AccumVal is non-nil, this is the type used to
107
* compute accumulated values. Must be a class type supporting
108
* three operations: empty(), project(Val) and merge(AccumVal,
109
* AccumVal), where empty() produces an AccumVal corresponding to
110
* an empty set, project() computes the AccumVal associated with a
111
* single value, and merge() combines two AccumVals. merge() must
112
* be associative and commutative.
114
* \tparam the weighting value of the tree; must be at least 3.75.
65
template<typename Val, const int w = 4>
116
template<typename Val, typename AccumVal = nil_t, typename AccumOps = nil_t, const int w = 4>
68
119
// Type hack to let us dump trees containing pairs without
92
143
/** Left and right children (may be \b null). */
93
144
wtree_node left, right;
95
/** The size of the subtree rooted at this node. */
146
/** The size of the subtree rooted at this node, paired with any
147
* accumulated information specified by the user.
149
* Using compressed_pair allows us to avoid allocating space if
150
* the accumulated value is empty, without having to contain an
151
* implementation of empty member elision.
153
boost::compressed_pair<size_type, AccumVal> sizeAndAccumVal;
98
155
/** The reference-count of this node. */
99
156
mutable int refcount;
101
158
/** The enclosed value. */
104
162
impl(const Val &_val,
105
const wtree_node &_left, const wtree_node &_right)
106
:left(_left), right(_right), size(_left.size()+_right.size()+1),
163
const wtree_node &_left, const wtree_node &_right,
165
:left(_left), right(_right),
166
sizeAndAccumVal(_left.size() + _right.size() + 1,
167
doAccumulate<Val, AccumVal, AccumOps, w>::call(_val, _left, _right, ops)),
107
168
refcount(1), val(_val)
172
impl *clone(const AccumOps &ops) const
174
return new impl(val, left.clone(ops), right.clone(ops), ops);
111
177
/** \return the left child. */
112
178
const wtree_node &getLeftChild() const
153
222
typedef unsigned int size_type;
155
224
wtree_node(const Val &val,
156
const wtree_node &left, const wtree_node &right)
157
:realNode(new impl(val, left, right))
225
const wtree_node &left, const wtree_node &right,
226
const AccumOps &accumOps)
227
:realNode(new impl(val, left, right, accumOps))
161
wtree_node(const Val &val)
162
:realNode(new impl(val, wtree_node(), wtree_node()))
231
wtree_node(const Val &val,
232
const AccumOps &accumOps)
233
:realNode(new impl(val, wtree_node(), wtree_node(),
247
319
return realNode->getVal();
322
/** \return the accumulated value of this node.
324
* Only allowed if AccumVal is non-nil and isValid() is truea.
326
const AccumVal &getAccumVal() const
328
return realNode->getAccumVal();
250
331
// Tree management routines:
252
333
/** Perform a 'left rotate' operation on this node. Requires
253
334
* that the right child is not \b null.
255
wtree_node left_rotate_single() const
336
wtree_node left_rotate_single(const AccumOps &accumOps) const
257
338
wtree_node right = getRight(), left = getLeft();
258
339
wtree_node right_left = right.getLeft(), right_right = right.getRight();
260
341
return wtree_node(right.getVal(),
261
wtree_node(getVal(), left, right_left),
342
wtree_node(getVal(), left, right_left, accumOps),
265
347
/** Perform a 'right rotate' operation on this node. Requires
266
348
* that the left child is not \b null.
268
wtree_node right_rotate_single() const
350
wtree_node right_rotate_single(const AccumOps &accumOps) const
270
352
wtree_node right = getRight(), left = getLeft();
271
353
wtree_node left_left = left.getLeft(), left_right = left.getRight();
273
355
return wtree_node(left.getVal(),
275
wtree_node(getVal(), left_right, right));
357
wtree_node(getVal(), left_right, right, accumOps),
278
361
/** Perform a 'double left rotate' operation on this node.
279
362
* Requires that the right child not be \b null and that
280
363
* its left child is also not \b null.
282
wtree_node left_rotate_double() const
365
wtree_node left_rotate_double(const AccumOps &accumOps) const
284
367
wtree_node right = getRight(), left = getLeft();
285
368
wtree_node right_right = right.getRight(), right_left = right.getLeft();
287
370
wtree_node right_left_right = right_left.getRight();
289
372
return wtree_node(right_left.getVal(),
290
wtree_node(getVal(), left, right_left_left),
373
wtree_node(getVal(), left, right_left_left, accumOps),
291
374
wtree_node(right.getVal(), right_left_right,
375
right_right, accumOps),
295
379
/** Perform a 'double right rotate' operation on this node.
296
380
* Requires that the left child not be \b null and that
297
381
* its right child is also not \b null.
299
wtree_node right_rotate_double() const
383
wtree_node right_rotate_double(const AccumOps &accumOps) const
301
385
wtree_node right = getRight(), left = getLeft();
302
386
wtree_node left_right = left.getRight(), left_left = left.getLeft();
304
388
wtree_node left_right_right = left_right.getRight();
306
390
return wtree_node(left_right.getVal(),
307
wtree_node(left.getVal(), left_left, left_right_left),
308
wtree_node(getVal(), left_right_right, right));
391
wtree_node(left.getVal(), left_left, left_right_left,
393
wtree_node(getVal(), left_right_right, right,
334
421
// double rotation is guaranteed sufficient.
335
422
wtree_node right_left = right.getLeft(), right_right = right.getRight();
336
423
if(right_left.size() < right_right.size())
337
return left_rotate_single();
424
return left_rotate_single(accumOps);
339
return left_rotate_double();
426
return left_rotate_double(accumOps);
341
428
else if(right_size * w < left_size)
343
430
// Dual of above.
344
431
wtree_node left_left = left.getLeft(), left_right = left.getRight();
345
432
if(left_right.size() < left_left.size())
346
return right_rotate_single();
433
return right_rotate_single(accumOps);
348
return right_rotate_double();
435
return right_rotate_double(accumOps);
351
438
// Nothing to do; the tree is already balanced.
402
489
/** Return a new tree that does not share its structure with any
405
wtree_node clone() const
492
wtree_node clone(const AccumOps &ops) const
408
495
return wtree_node();
410
return wtree_node(getVal(), getLeft().clone(), getRight().clone());
497
return wtree_node(realNode->clone(ops));
501
template<typename Val, typename AccumVal, typename AccumOps, int w>
503
doAccumulate<Val, AccumVal, AccumOps, w>::call(const Val &val,
504
const wtree_node<Val, AccumVal, AccumOps, w> &left,
505
const wtree_node<Val, AccumVal, AccumOps, w> &right,
506
const AccumOps &accumOps)
508
if(left.isValid() && right.isValid())
510
const AccumVal valAndRight =
511
accumOps.merge(accumOps.project(val),
512
right.getAccumVal());
513
return accumOps.merge(left.getAccumVal(),
516
else if(left.isValid())
517
return accumOps.merge(left.getAccumVal(),
518
accumOps.project(val));
519
else if(right.isValid())
520
return accumOps.merge(accumOps.project(val),
521
right.getAccumVal());
523
return accumOps.project(val);
526
template<typename Val, typename AccumVal, int w>
527
class doAccumulate<Val, AccumVal, nil_t, w>
530
static inline AccumVal
532
const wtree_node<Val, AccumVal, nil_t, w> &left,
533
const wtree_node<Val, AccumVal, nil_t, w> &right,
534
const nil_t &accumOps)
414
541
/** An entire weighted tree.
543
* \tparam AccumVal if non-nil, a value of this type will be
544
* computed that represents the combination of all the values in
545
* the tree under AccumOps.
547
* \tparam AccumOps A class type that allows values to be combined;
548
* documented under wtree_node.
416
template<typename Val, typename Compare = aptitude::util::compare3_f<Val>, int w = 4 >
550
template<typename Val, typename Compare = aptitude::util::compare3_f<Val>,
551
typename AccumVal = nil_t, typename AccumOps = nil_t, int w = 4 >
420
555
typedef Val value_type;
421
typedef wtree_node<Val, w> node;
556
typedef wtree_node<Val, AccumVal, AccumOps, w> node;
422
557
typedef typename node::size_type size_type;
424
Compare value_compare;
426
559
/** An iterator over a wtree. Note that the lack of parent
427
560
* pointers (necessary to allow full memory sharing) forces the
428
561
* iterator class to allocate! I don't recommend using iterators
516
/** Root of the tree. */
649
// Save space by throwing out empty comparison operators and
650
// accumulation operators.
653
boost::compressed_pair<Compare, boost::compressed_pair<AccumOps, node> >
657
contents(const node &root,
658
const Compare &value_compare,
659
const AccumOps &accumOps)
660
: rootAndParameters(value_compare,
661
boost::compressed_pair<AccumOps, node>(accumOps, root))
665
const Compare &get_value_compare() const { return rootAndParameters.first(); }
666
const AccumOps &get_accumOps() const { return rootAndParameters.second().first(); }
667
const node &get_root() const { return rootAndParameters.second().second(); }
668
void set_root(const node &n) { rootAndParameters.second().second() = n; }
519
673
/** Returns a balanced tree constructed by adding x to n.
524
678
node add(const node &n, const Val &x, bool &added_anything) const
527
return node(x, node(), node());
681
return node(x, node(), node(), impl.get_accumOps());
530
int cmp = value_compare(x, n.getVal());
684
int cmp = impl.get_value_compare()(x, n.getVal());
533
687
return node(n.getVal(),
534
688
add(n.getLeft(), x, added_anything),
535
n.getRight()).rebalance();
690
impl.get_accumOps()).rebalance(impl.get_accumOps());
537
692
return node(n.getVal(),
539
add(n.getRight(), x, added_anything)).rebalance();
694
add(n.getRight(), x, added_anything),
695
impl.get_accumOps()).rebalance(impl.get_accumOps());
542
698
added_anything = false;
554
710
node addUpdate(const node &n, const Val &x, bool &added_new_entry) const
557
return node(x, node(), node());
713
return node(x, node(), node(), impl.get_accumOps());
560
int cmp = value_compare(x, n.getVal());
716
int cmp = impl.get_value_compare()(x, n.getVal());
563
719
return node(n.getVal(),
564
720
addUpdate(n.getLeft(), x, added_new_entry),
565
n.getRight()).rebalance();
722
impl.get_accumOps()).rebalance(impl.get_accumOps());
567
724
return node(n.getVal(),
569
addUpdate(n.getRight(), x, added_new_entry)).rebalance();
726
addUpdate(n.getRight(), x, added_new_entry),
727
impl.get_accumOps()).rebalance(impl.get_accumOps());
572
730
added_new_entry = false;
573
return node(x, n.getLeft(), n.getRight());
731
return node(x, n.getLeft(), n.getRight(), impl.get_accumOps());
579
737
* simultaneously constructing a new (balanced) node that doesn't
580
738
* contain the minimum.
582
static std::pair<node, Val> find_and_remove_min(const node &n)
740
static std::pair<node, Val> find_and_remove_min(const node &n,
741
const AccumOps &accumOps)
584
743
if(n.getLeft().isValid())
586
std::pair<node, Val> tmp = find_and_remove_min(n.getLeft());
745
std::pair<node, Val> tmp = find_and_remove_min(n.getLeft(), accumOps);
587
746
return std::pair<node, Val>(node(n.getVal(),
588
tmp.first, n.getRight()).rebalance(),
747
tmp.first, n.getRight(),
748
accumOps).rebalance(accumOps),
597
757
/** Join together two trees; every element of l must be less than
598
758
* every element of r.
600
static node splice_trees(const node &l, const node &r)
760
static node splice_trees(const node &l, const node &r,
761
const AccumOps &accumOps)
604
765
else if(l.empty())
607
std::pair<node, Val> tmp = find_and_remove_min(r);
608
return node(tmp.second, l, tmp.first);
768
std::pair<node, Val> tmp = find_and_remove_min(r, accumOps);
769
return node(tmp.second, l, tmp.first, accumOps);
611
772
/** \return \b true if there exist elements x1 and x2 in n1 and n2
662
int cmp = value_compare(n1.getVal(), n2.getVal());
823
int cmp = impl.get_value_compare()(n1.getVal(), n2.getVal());
666
827
// Strip the left subtree of n2.
667
828
node n2repl = n2.getLeft().empty()
668
? n2 : node(n2.getVal(), node(), n2.getRight());
829
? n2 : node(n2.getVal(), node(), n2.getRight(),
830
impl.get_accumOps());
670
832
return node_contains(n1, n2.getLeft(), f) &&
671
833
node_contains(n1.getRight(), n2repl, f);
675
837
// Strip the right subtree of n2.
676
838
node n2repl = n2.getRight().empty()
677
? n2 : node(n2.getVal(), n2.getLeft(), node());
839
? n2 : node(n2.getVal(), n2.getLeft(), node(),
840
impl.get_accumOps());
679
842
return node_contains(n1, n2.getRight(), f) &&
680
843
node_contains(n1.getLeft(), n2repl, f);
698
const int cmp = value_compare(x, n.getVal());
861
const int cmp = impl.get_value_compare()(x, n.getVal());
701
864
return node(n.getVal(),
702
865
remove(n.getLeft(), x, removed_anything),
703
n.getRight()).rebalance();
867
impl.get_accumOps()).rebalance(impl.get_accumOps());
705
869
return node(n.getVal(),
707
remove(n.getRight(), x, removed_anything)).rebalance();
871
remove(n.getRight(), x, removed_anything),
872
impl.get_accumOps()).rebalance(impl.get_accumOps());
708
873
else // found an equivalent node:
710
875
removed_anything = true;
711
return splice_trees(n.getLeft(), n.getRight());
876
return splice_trees(n.getLeft(), n.getRight(), impl.get_accumOps());
716
set(const node &n, const Compare &_value_compare)
717
:value_compare(_value_compare), root(n)
881
set(const node &n, const Compare &value_compare, const AccumOps &accumOps)
882
: impl(n, value_compare, accumOps)
749
915
static set add(const set &old, const Val &x, bool &added_anything)
751
return set(old.add(old.root, x, added_anything), old.value_compare);
917
return set(old.add(old.impl.get_root(), x, added_anything),
918
old.impl.get_value_compare(),
919
old.impl.get_accumOps());
754
922
static set add(const set &old, const Val &x)
760
928
/** Like add, but updates existing equivalent elements. */
761
929
static set addUpdate(const set &old, const Val &x, bool &added_new_entry)
763
return set(old.addUpdate(old.root, x, added_new_entry), old.value_compare);
931
return set(old.addUpdate(old.impl.get_root(), x, added_new_entry),
932
old.impl.get_value_compare(),
933
old.impl.get_accumOps());
766
936
static set addUpdate(const set &old, const Val &x)
773
943
static set remove(const set &old, const Val &x, bool &removed_anything)
775
945
removed_anything = false;
776
return set(old.remove(old.root, x, removed_anything), old.value_compare);
946
return set(old.remove(old.impl.get_root(), x, removed_anything),
947
old.impl.get_value_compare(),
948
old.impl.get_accumOps());
779
951
static set remove(const set &old, const Val &x)
789
961
template<typename F>
790
962
bool intersects(const set &other, const F &f) const
792
return nodes_intersect(root, other.root, f);
964
return nodes_intersect(impl.get_root(), other.impl.get_root(), f);
795
967
/** \return \b true if this set intersects the given set. */
796
968
bool intersects(const set &other) const
798
return nodes_intersect(root, other.root, universal_relation<Val>());
970
return nodes_intersect(impl.get_root(), other.impl.get_root(), universal_relation<Val>());
801
973
/** \return \b true if each element of other is related by f to an
954
1137
/** \brief Write a set to a stream as a set (values are written with
957
template<typename Val, typename Compare, int w>
958
std::ostream &operator<<(std::ostream &out, const set<Val, Compare, w> &s)
1140
template<typename Val, typename Compare, typename AccumVal, typename AccumOps, int w>
1141
std::ostream &operator<<(std::ostream &out, const set<Val, Compare, AccumVal, AccumOps, w> &s)
961
1144
set_write_action<Val> act(out);
975
1158
* ensuring that this is the case. (i.e., if the comparator has
976
1159
* associated data, it should be identical in the two sets)
978
template<typename Val, typename Compare, int w>
979
class compare3_f<imm::set<Val, Compare, w> >
1161
template<typename Val, typename Compare, typename AccumVal, typename AccumOps, int w>
1162
class compare3_f<imm::set<Val, Compare, AccumVal, AccumOps, w> >
982
int operator()(const imm::set<Val, Compare, w> &s1,
983
const imm::set<Val, Compare, w> &s2) const
1165
int operator()(const imm::set<Val, Compare, AccumVal, AccumOps, w> &s1,
1166
const imm::set<Val, Compare, AccumVal, AccumOps, w> &s2) const
985
1168
return aptitude::util::lexicographical_compare3(s1.begin(), s1.end(),
986
1169
s2.begin(), s2.end());
994
template<typename Val, typename Compare, int w>
995
inline bool operator<(const set<Val, Compare, w> &s1,
996
const set<Val, Compare, w> &s2)
1177
template<typename Val, typename Compare, typename AccumVal, typename AccumOps, int w>
1178
inline bool operator<(const set<Val, Compare, AccumVal, AccumOps, w> &s1,
1179
const set<Val, Compare, AccumVal, AccumOps, w> &s2)
998
1181
return aptitude::util::compare3(s1, s2) < 0;
1001
1184
/** Compare two sets for equality, with the same caveat as operator<. */
1002
template<typename Val, typename Compare, int w>
1003
inline bool operator==(const set<Val, Compare, w> &s1,
1004
const set<Val, Compare, w> &s2)
1185
template<typename Val, typename Compare, typename AccumVal, typename AccumOps, int w>
1186
inline bool operator==(const set<Val, Compare, AccumVal, AccumOps, w> &s1,
1187
const set<Val, Compare, AccumVal, AccumOps, w> &s2)
1006
typename set<Val, Compare, w>::const_iterator
1189
typename set<Val, Compare, AccumVal, AccumOps, w>::const_iterator
1007
1190
i1 = s1.begin(), i2 = s2.begin();
1009
1192
while(i1 != s1.end() && i2 != s2.end())
1042
template<typename Key, typename Val, typename Compare = aptitude::util::compare3_f<Key> >
1225
template<typename Key, typename Val, typename Compare = aptitude::util::compare3_f<Key>,
1226
typename AccumVal = nil_t,
1227
typename AccumOps = nil_t>
1046
1231
typedef std::pair<Key, Val> binding_type;
1047
typedef set<binding_type, key_compare<Key, Val, Compare> > mapping_type;
1232
typedef set<binding_type, key_compare<Key, Val, Compare>, AccumVal, AccumOps> mapping_type;
1048
1233
typedef typename mapping_type::const_iterator const_iterator;
1049
1234
typedef typename mapping_type::size_type size_type;
1050
1235
typedef typename mapping_type::node node;
1062
1247
/** Construct an empty map */
1063
map(const Compare &value_compare = Compare())
1064
:contents(mapping_type(key_compare<Key, Val, Compare>(value_compare)))
1248
map(const Compare &value_compare = Compare(),
1249
const AccumOps &accumOps = AccumOps())
1250
:contents(mapping_type(key_compare<Key, Val, Compare>(value_compare),
1251
1444
/** \brief Write a map to a stream as a map (values are written with
1254
template<typename Key, typename Val, typename Compare>
1255
std::ostream &operator<<(std::ostream &out, const map<Key, Val, Compare> &m)
1447
template<typename Key, typename Val, typename Compare, typename AccumVal, typename AccumOps>
1448
std::ostream &operator<<(std::ostream &out, const map<Key, Val, Compare, AccumVal, AccumOps> &m)
1274
1467
* ensuring that this is the case. (i.e., if the comparator has
1275
1468
* associated data, it should be identical in the two sets)
1277
template<typename Key, typename Val, typename Compare>
1278
class compare3_f<imm::map<Key, Val, Compare> >
1470
template<typename Key, typename Val, typename Compare, typename AccumVal, typename AccumOps>
1471
class compare3_f<imm::map<Key, Val, Compare, AccumVal, AccumOps> >
1281
int operator()(const imm::map<Key, Val, Compare> &m1,
1282
const imm::map<Key, Val, Compare> &m2) const
1474
int operator()(const imm::map<Key, Val, Compare, AccumVal, AccumOps> &m1,
1475
const imm::map<Key, Val, Compare, AccumVal, AccumOps> &m2) const
1284
1477
return compare3(m1.get_bindings(), m2.get_bindings());