//===-- ImmutableTree.h -----------------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef KLEE_IMMUTABLETREE_H #define KLEE_IMMUTABLETREE_H #include #include namespace klee { template class ImmutableTree { public: static size_t allocated; class iterator; typedef K key_type; typedef V value_type; typedef KOV key_of_value; typedef CMP key_compare; public: ImmutableTree(); ImmutableTree(const ImmutableTree &s); ~ImmutableTree(); ImmutableTree &operator=(const ImmutableTree &s); bool empty() const; size_t count(const key_type &key) const; // always 0 or 1 const value_type *lookup(const key_type &key) const; // find the last value less than or equal to key, or null if // no such value exists const value_type *lookup_previous(const key_type &key) const; const value_type &min() const; const value_type &max() const; size_t size() const; ImmutableTree insert(const value_type &value) const; ImmutableTree replace(const value_type &value) const; ImmutableTree remove(const key_type &key) const; ImmutableTree popMin(value_type &valueOut) const; ImmutableTree popMax(value_type &valueOut) const; iterator begin() const; iterator end() const; iterator find(const key_type &key) const; iterator lower_bound(const key_type &key) const; iterator upper_bound(const key_type &key) const; static size_t getAllocated() { return allocated; } private: class Node; Node *node; ImmutableTree(Node *_node); }; /***/ template class ImmutableTree::Node { public: static Node terminator; Node *left, *right; value_type value; unsigned height, references; protected: Node(); // solely for creating the terminator node static Node *balance(Node *left, const value_type &value, Node *right); public: Node(Node *_left, Node *_right, const value_type &_value); ~Node(); void decref(); Node *incref(); bool isTerminator(); size_t size(); Node *popMin(value_type &valueOut); Node *popMax(value_type &valueOut); Node *insert(const value_type &v); Node *replace(const value_type &v); Node *remove(const key_type &k); }; // Should live somewhere else, this is a simple stack with maximum (dynamic) // size. template class FixedStack { unsigned pos, max; T *elts; public: FixedStack(unsigned _max) : pos(0), max(_max), elts(new T[max]) {} FixedStack(const FixedStack &b) : pos(b.pos), max(b.max), elts(new T[b.max]) { std::copy(b.elts, b.elts+pos, elts); } ~FixedStack() { delete[] elts; } void push_back(const T &elt) { elts[pos++] = elt; } void pop_back() { --pos; } bool empty() { return pos==0; } T &back() { return elts[pos-1]; } FixedStack &operator=(const FixedStack &b) { assert(max == b.max); pos = b.pos; std::copy(b.elts, b.elts+pos, elts); return *this; } bool operator==(const FixedStack &b) { return (pos == b.pos && std::equal(elts, elts+pos, b.elts)); } bool operator!=(const FixedStack &b) { return !(*this==b); } }; template class ImmutableTree::iterator { friend class ImmutableTree; private: Node *root; // so can back up from end FixedStack stack; public: iterator(Node *_root, bool atBeginning) : root(_root->incref()), stack(root->height) { if (atBeginning) { for (Node *n=root; !n->isTerminator(); n=n->left) stack.push_back(n); } } iterator(const iterator &i) : root(i.root->incref()), stack(i.stack) { } ~iterator() { root->decref(); } iterator &operator=(const iterator &b) { b.root->incref(); root->decref(); root = b.root; stack = b.stack; return *this; } const value_type &operator*() { Node *n = stack.back(); return n->value; } const value_type *operator->() { Node *n = stack.back(); return &n->value; } bool operator==(const iterator &b) { return stack==b.stack; } bool operator!=(const iterator &b) { return stack!=b.stack; } iterator &operator--() { if (stack.empty()) { for (Node *n=root; !n->isTerminator(); n=n->right) stack.push_back(n); } else { Node *n = stack.back(); if (n->left->isTerminator()) { for (;;) { Node *prev = n; stack.pop_back(); if (stack.empty()) { break; } else { n = stack.back(); if (prev==n->right) break; } } } else { stack.push_back(n->left); for (n=n->left->right; !n->isTerminator(); n=n->right) stack.push_back(n); } } return *this; } iterator &operator++() { assert(!stack.empty()); Node *n = stack.back(); if (n->right->isTerminator()) { for (;;) { Node *prev = n; stack.pop_back(); if (stack.empty()) { break; } else { n = stack.back(); if (prev==n->left) break; } } } else { stack.push_back(n->right); for (n=n->right->left; !n->isTerminator(); n=n->left) stack.push_back(n); } return *this; } }; /***/ template typename ImmutableTree::Node ImmutableTree::Node::terminator; template size_t ImmutableTree::allocated = 0; template ImmutableTree::Node::Node() : left(&terminator), right(&terminator), height(0), references(3) { assert(this==&terminator); } template ImmutableTree::Node::Node(Node *_left, Node *_right, const value_type &_value) : left(_left), right(_right), value(_value), height(std::max(left->height, right->height) + 1), references(1) { ++allocated; } template ImmutableTree::Node::~Node() { left->decref(); right->decref(); --allocated; } template inline void ImmutableTree::Node::decref() { --references; if (references==0) delete this; } template inline typename ImmutableTree::Node *ImmutableTree::Node::incref() { ++references; return this; } template inline bool ImmutableTree::Node::isTerminator() { return this==&terminator; } /***/ template typename ImmutableTree::Node * ImmutableTree::Node::balance(Node *left, const value_type &value, Node *right) { if (left->height > right->height + 2) { Node *ll = left->left; Node *lr = left->right; if (ll->height >= lr->height) { Node *nlr = new Node(lr->incref(), right, value); Node *res = new Node(ll->incref(), nlr, left->value); left->decref(); return res; } else { Node *lrl = lr->left; Node *lrr = lr->right; Node *nll = new Node(ll->incref(), lrl->incref(), left->value); Node *nlr = new Node(lrr->incref(), right, value); Node *res = new Node(nll, nlr, lr->value); left->decref(); return res; } } else if (right->height > left->height + 2) { Node *rl = right->left; Node *rr = right->right; if (rr->height >= rl->height) { Node *nrl = new Node(left, rl->incref(), value); Node *res = new Node(nrl, rr->incref(), right->value); right->decref(); return res; } else { Node *rll = rl->left; Node *rlr = rl->right; Node *nrl = new Node(left, rll->incref(), value); Node *nrr = new Node(rlr->incref(), rr->incref(), right->value); Node *res = new Node(nrl, nrr, rl->value); right->decref(); return res; } } else { return new Node(left, right, value); } } template size_t ImmutableTree::Node::size() { if (isTerminator()) { return 0; } else { return left->size() + 1 + right->size(); } } template typename ImmutableTree::Node * ImmutableTree::Node::popMin(value_type &valueOut) { if (left->isTerminator()) { valueOut = value; return right->incref(); } else { return balance(left->popMin(valueOut), value, right->incref()); } } template typename ImmutableTree::Node * ImmutableTree::Node::popMax(value_type &valueOut) { if (right->isTerminator()) { valueOut = value; return left->incref(); } else { return balance(left->incref(), value, right->popMax(valueOut)); } } template typename ImmutableTree::Node * ImmutableTree::Node::insert(const value_type &v) { if (isTerminator()) { return new Node(terminator.incref(), terminator.incref(), v); } else { if (key_compare()(key_of_value()(v), key_of_value()(value))) { return balance(left->insert(v), value, right->incref()); } else if (key_compare()(key_of_value()(value), key_of_value()(v))) { return balance(left->incref(), value, right->insert(v)); } else { return incref(); } } } template typename ImmutableTree::Node * ImmutableTree::Node::replace(const value_type &v) { if (isTerminator()) { return new Node(terminator.incref(), terminator.incref(), v); } else { if (key_compare()(key_of_value()(v), key_of_value()(value))) { return balance(left->replace(v), value, right->incref()); } else if (key_compare()(key_of_value()(value), key_of_value()(v))) { return balance(left->incref(), value, right->replace(v)); } else { return new Node(left->incref(), right->incref(), v); } } } template typename ImmutableTree::Node * ImmutableTree::Node::remove(const key_type &k) { if (isTerminator()) { return incref(); } else { if (key_compare()(k, key_of_value()(value))) { return balance(left->remove(k), value, right->incref()); } else if (key_compare()(key_of_value()(value), k)) { return balance(left->incref(), value, right->remove(k)); } else { if (left->isTerminator()) { return right->incref(); } else if (right->isTerminator()) { return left->incref(); } else { value_type min; Node *nr = right->popMin(min); return balance(left->incref(), min, nr); } } } } /***/ template ImmutableTree::ImmutableTree() : node(Node::terminator.incref()) { } template ImmutableTree::ImmutableTree(Node *_node) : node(_node) { } template ImmutableTree::ImmutableTree(const ImmutableTree &s) : node(s.node->incref()) { } template ImmutableTree::~ImmutableTree() { node->decref(); } template ImmutableTree &ImmutableTree::operator=(const ImmutableTree &s) { Node *n = s.node->incref(); node->decref(); node = n; return *this; } template bool ImmutableTree::empty() const { return node->isTerminator(); } template size_t ImmutableTree::count(const key_type &k) const { Node *n = node; while (!n->isTerminator()) { key_type key = key_of_value()(n->value); if (key_compare()(k, key)) { n = n->left; } else if (key_compare()(key, k)) { n = n->right; } else { return 1; } } return 0; } template const typename ImmutableTree::value_type * ImmutableTree::lookup(const key_type &k) const { Node *n = node; while (!n->isTerminator()) { key_type key = key_of_value()(n->value); if (key_compare()(k, key)) { n = n->left; } else if (key_compare()(key, k)) { n = n->right; } else { return &n->value; } } return 0; } template const typename ImmutableTree::value_type * ImmutableTree::lookup_previous(const key_type &k) const { Node *n = node; Node *result = 0; while (!n->isTerminator()) { key_type key = key_of_value()(n->value); if (key_compare()(k, key)) { n = n->left; } else if (key_compare()(key, k)) { result = n; n = n->right; } else { return &n->value; } } return result ? &result->value : 0; } template const typename ImmutableTree::value_type & ImmutableTree::min() const { Node *n = node; assert(!n->isTerminator()); while (!n->left->isTerminator()) n = n->left; return n->value; } template const typename ImmutableTree::value_type & ImmutableTree::max() const { Node *n = node; assert(!n->isTerminator()); while (!n->right->isTerminator()) n = n->right; return n->value; } template size_t ImmutableTree::size() const { return node->size(); } template ImmutableTree ImmutableTree::insert(const value_type &value) const { return ImmutableTree(node->insert(value)); } template ImmutableTree ImmutableTree::replace(const value_type &value) const { return ImmutableTree(node->replace(value)); } template ImmutableTree ImmutableTree::remove(const key_type &key) const { return ImmutableTree(node->remove(key)); } template ImmutableTree ImmutableTree::popMin(value_type &valueOut) const { return ImmutableTree(node->popMin(valueOut)); } template ImmutableTree ImmutableTree::popMax(value_type &valueOut) const { return ImmutableTree(node->popMax(valueOut)); } template inline typename ImmutableTree::iterator ImmutableTree::begin() const { return iterator(node, true); } template inline typename ImmutableTree::iterator ImmutableTree::end() const { return iterator(node, false); } template inline typename ImmutableTree::iterator ImmutableTree::find(const key_type &key) const { iterator end(node,false), it = lower_bound(key); if (it==end || key_compare()(key,key_of_value()(*it))) { return end; } else { return it; } } template inline typename ImmutableTree::iterator ImmutableTree::lower_bound(const key_type &k) const { // XXX ugh this doesn't have to be so ugly does it? iterator it(node,false); for (Node *root=node; !root->isTerminator();) { it.stack.push_back(root); if (key_compare()(k, key_of_value()(root->value))) { root = root->left; } else if (key_compare()(key_of_value()(root->value), k)) { root = root->right; } else { return it; } } // it is now beginning or first element < k if (!it.stack.empty()) { Node *last = it.stack.back(); if (key_compare()(key_of_value()(last->value), k)) ++it; } return it; } template typename ImmutableTree::iterator ImmutableTree::upper_bound(const key_type &key) const { iterator end(node,false),it = lower_bound(key); if (it!=end && !key_compare()(key,key_of_value()(*it))) // no need to loop, no duplicates ++it; return it; } } #endif /* KLEE_IMMUTABLETREE_H */