dReal4
scoped_unordered_set.h
1 #pragma once
2 
3 #include <functional>
4 #include <iostream>
5 #include <memory>
6 #include <tuple>
7 #include <unordered_set>
8 #include <utility>
9 #include <vector>
10 
11 #include "dreal/util/exception.h"
12 
13 namespace dreal {
14 
15 /// Backtrackable set.
16 
17 template <class Key, class Hash = std::hash<Key>,
18  class KeyEqual = std::equal_to<Key>,
19  class Allocator = std::allocator<Key>>
21  public:
22  /// Aliases.
23  using UnorderedSetType = std::unordered_set<Key, Hash, KeyEqual, Allocator>;
24  using key_type = typename UnorderedSetType::key_type;
25  using value_type = typename UnorderedSetType::value_type;
26  using size_type = typename UnorderedSetType::size_type;
27  using const_iterator = typename UnorderedSetType::const_iterator;
28 
29  /// To backtrack, we need to record the actions applied to this
30  /// container.
31  enum class ActionKind {
32  INSERT, ///< Insert(k) means that k is inserted.
33  };
34  using Action = std::tuple<ActionKind, Key>;
35 
36  ScopedUnorderedSet() = default;
37  ScopedUnorderedSet(const ScopedUnorderedSet&) = default;
38  ScopedUnorderedSet(ScopedUnorderedSet&&) noexcept = default;
39  ScopedUnorderedSet& operator=(const ScopedUnorderedSet&) = default;
40  ScopedUnorderedSet& operator=(ScopedUnorderedSet&&) noexcept = default;
41  ~ScopedUnorderedSet() = default;
42 
43  /// Iterators.
44  ///
45  /// @note We only provide 'const' iterators because any modification
46  /// should be done explicitly via its APIs so that we can keep track
47  /// of changes and undo when pop() is called.
48  const_iterator begin() const { return set_.begin(); }
49  const_iterator cbegin() const { return set_.cbegin(); }
50  const_iterator end() const { return set_.end(); }
51  const_iterator cend() const { return set_.cend(); }
52 
53  /// Capacity
54  bool empty() const { return set_.empty(); }
55  size_type size() const { return set_.size(); }
56 
57  /// Modifiers
58  void clear() {
59  set_.clear();
60  actions_.clear();
61  stack_.clear();
62  }
63  void insert(const Key& k) {
64  auto it = set_.find(k);
65  if (it == set_.end()) {
66  // Case 1) k does not exist.
67  actions_.emplace_back(ActionKind::INSERT, k);
68  set_.emplace(k);
69  }
70  }
71 
72  size_type count(const Key& key) const { return set_.count(key); }
73  /// @note It returns 'const' iterator.
74  const_iterator find(const Key& key) const { return set_.find(key); }
75 
76  /// Push/Pop
77  void push() { stack_.push_back(actions_.size()); }
78  void pop() {
79  if (stack_.empty()) {
80  throw DREAL_RUNTIME_ERROR(
81  "ScopedUnorderedSet cannot be popped because it's scope is empty.");
82  }
83  size_type idx = stack_.back();
84  while (idx < actions_.size()) {
85  const Action& item{actions_.back()};
86  const ActionKind kind{std::get<0>(item)};
87  const Key& k{std::get<1>(item)};
88  auto it = set_.find(k);
89  switch (kind) {
90  case ActionKind::INSERT:
91  // Remove k.
92  set_.erase(it);
93  break;
94  }
95  actions_.pop_back();
96  }
97  stack_.pop_back();
98  }
99 
100  private:
101  std::vector<Action> actions_;
102  std::vector<size_type> stack_;
103  UnorderedSetType set_;
104 };
105 } // namespace dreal
Sum type of symbolic::Expression and symbolic::Formula.
Definition: api.cc:9
Backtrackable set.
Definition: scoped_unordered_set.h:20
std::unordered_set< Variable::Id, std::hash< Variable::Id >, std::equal_to< Variable::Id >, std::allocator< Variable::Id > > UnorderedSetType
Aliases.
Definition: scoped_unordered_set.h:23
void push()
Push/Pop.
Definition: scoped_unordered_set.h:77
const_iterator find(const Key &key) const
Definition: scoped_unordered_set.h:74
Insert(k) means that k is inserted.
void clear()
Modifiers.
Definition: scoped_unordered_set.h:58
bool empty() const
Capacity.
Definition: scoped_unordered_set.h:54
const_iterator begin() const
Iterators.
Definition: scoped_unordered_set.h:48
ActionKind
To backtrack, we need to record the actions applied to this container.
Definition: scoped_unordered_set.h:31