about summary refs log tree commit diff homepage
path: root/include/klee/Internal/ADT/ImmutableTree.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/klee/Internal/ADT/ImmutableTree.h')
-rw-r--r--include/klee/Internal/ADT/ImmutableTree.h619
1 files changed, 619 insertions, 0 deletions
diff --git a/include/klee/Internal/ADT/ImmutableTree.h b/include/klee/Internal/ADT/ImmutableTree.h
new file mode 100644
index 00000000..2f294077
--- /dev/null
+++ b/include/klee/Internal/ADT/ImmutableTree.h
@@ -0,0 +1,619 @@
+//===-- 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 __UTIL_IMMUTABLETREE_H__
+#define __UTIL_IMMUTABLETREE_H__
+
+#include <cassert>
+#include <vector>
+
+namespace klee {
+  template<class K, class V, class KOV, class CMP>
+  class ImmutableTree {
+  public:
+    static unsigned 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;
+
+    unsigned 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;
+    unsigned 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 unsigned getAllocated() { return allocated; }
+
+  private:
+    class Node;
+
+    Node *node;
+    ImmutableTree(Node *_node);
+  };
+
+  /***/
+
+  template<class K, class V, class KOV, class CMP>
+  class ImmutableTree<K,V,KOV,CMP>::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();
+
+    unsigned 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 size.
+  template<typename T>
+  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 K, class V, class KOV, class CMP>
+  class ImmutableTree<K,V,KOV,CMP>::iterator {
+    friend class ImmutableTree<K,V,KOV,CMP>;
+  private:
+    Node *root; // so can back up from end
+    FixedStack<Node*> 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<class K, class V, class KOV, class CMP> 
+  typename ImmutableTree<K,V,KOV,CMP>::Node 
+  ImmutableTree<K,V,KOV,CMP>::Node::terminator;
+
+  template<class K, class V, class KOV, class CMP> 
+  unsigned ImmutableTree<K,V,KOV,CMP>::allocated = 0;
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::Node::Node() 
+    : left(&terminator), 
+      right(&terminator), 
+      height(0), 
+      references(3) { 
+    assert(this==&terminator);
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::Node::~Node() {
+    left->decref();
+    right->decref();
+    --allocated;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline void ImmutableTree<K,V,KOV,CMP>::Node::decref() {
+    --references;
+    if (references==0) delete this;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline typename ImmutableTree<K,V,KOV,CMP>::Node *ImmutableTree<K,V,KOV,CMP>::Node::incref() {
+    ++references;
+    return this;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline bool ImmutableTree<K,V,KOV,CMP>::Node::isTerminator() {
+    return this==&terminator;
+  }
+
+  /***/
+
+  template<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  unsigned ImmutableTree<K,V,KOV,CMP>::Node::size() {
+    if (isTerminator()) {
+      return 0;
+    } else {
+      return left->size() + 1 + right->size();
+    }
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::Node::popMin(value_type &valueOut) {
+    if (left->isTerminator()) {
+      valueOut = value;
+      return right->incref();
+    } else {
+      return balance(left->popMin(valueOut), value, right->incref());
+    }
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::Node::popMax(value_type &valueOut) {
+    if (right->isTerminator()) {
+      valueOut = value;
+      return left->incref();
+    } else {
+      return balance(left->incref(), value, right->popMax(valueOut));
+    }
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::Node *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::ImmutableTree() 
+    : node(Node::terminator.incref()) {
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::ImmutableTree(Node *_node) 
+    : node(_node) {
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::ImmutableTree(const ImmutableTree &s) 
+    : node(s.node->incref()) {
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP>::~ImmutableTree() {
+    node->decref(); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> &ImmutableTree<K,V,KOV,CMP>::operator=(const ImmutableTree &s) {
+    Node *n = s.node->incref();
+    node->decref();
+    node = n;
+    return *this;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  bool ImmutableTree<K,V,KOV,CMP>::empty() const {
+    return node->isTerminator();
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  unsigned ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  const typename ImmutableTree<K,V,KOV,CMP>::value_type *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  const typename ImmutableTree<K,V,KOV,CMP>::value_type *
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  const typename ImmutableTree<K,V,KOV,CMP>::value_type &
+  ImmutableTree<K,V,KOV,CMP>::min() const { 
+    Node *n = node;
+    assert(!n->isTerminator());
+    while (!n->left->isTerminator()) n = n->left;
+    return n->value;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  const typename ImmutableTree<K,V,KOV,CMP>::value_type &
+  ImmutableTree<K,V,KOV,CMP>::max() const {
+    Node *n = node;
+    assert(!n->isTerminator());
+    while (!n->right->isTerminator()) n = n->right;
+    return n->value;
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  unsigned ImmutableTree<K,V,KOV,CMP>::size() const {
+    return node->size();
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> 
+  ImmutableTree<K,V,KOV,CMP>::insert(const value_type &value) const { 
+    return ImmutableTree(node->insert(value)); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> 
+  ImmutableTree<K,V,KOV,CMP>::replace(const value_type &value) const { 
+    return ImmutableTree(node->replace(value)); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> 
+  ImmutableTree<K,V,KOV,CMP>::remove(const key_type &key) const { 
+    return ImmutableTree(node->remove(key)); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> 
+  ImmutableTree<K,V,KOV,CMP>::popMin(value_type &valueOut) const { 
+    return ImmutableTree(node->popMin(valueOut)); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  ImmutableTree<K,V,KOV,CMP> 
+  ImmutableTree<K,V,KOV,CMP>::popMax(value_type &valueOut) const { 
+    return ImmutableTree(node->popMax(valueOut)); 
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline typename ImmutableTree<K,V,KOV,CMP>::iterator 
+  ImmutableTree<K,V,KOV,CMP>::begin() const {
+    return iterator(node, true);
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline typename ImmutableTree<K,V,KOV,CMP>::iterator 
+  ImmutableTree<K,V,KOV,CMP>::end() const {
+    return iterator(node, false);
+  }
+
+  template<class K, class V, class KOV, class CMP>
+  inline typename ImmutableTree<K,V,KOV,CMP>::iterator 
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  inline typename ImmutableTree<K,V,KOV,CMP>::iterator 
+  ImmutableTree<K,V,KOV,CMP>::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<class K, class V, class KOV, class CMP>
+  typename ImmutableTree<K,V,KOV,CMP>::iterator 
+  ImmutableTree<K,V,KOV,CMP>::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