Kagome
Polkadot Runtime Engine in C++17
polkadot_trie_cursor_impl.hpp
Go to the documentation of this file.
1 
6 #ifndef KAGOME_CORE_STORAGE_TRIE_POLKADOT_TRIE_POLKADOT_TRIE_CURSOR_IMPL
7 #define KAGOME_CORE_STORAGE_TRIE_POLKADOT_TRIE_POLKADOT_TRIE_CURSOR_IMPL
8 
10 
11 #include "log/logger.hpp"
13 
14 namespace kagome::storage::trie {
15 
16  class PolkadotTrie;
17 
19  public:
21 
22  enum class Error {
23  // cursor stumbled upon a node with a type invalid in the given context
24  // (e.g. a leaf node where a branch node should've been)
26  // operation cannot be performed for cursor position is not valid
27  // due to an error, reaching the end or not calling next() after
28  // initialization
31  };
32 
33  explicit PolkadotTrieCursorImpl(std::shared_ptr<const PolkadotTrie> trie);
34 
35  ~PolkadotTrieCursorImpl() override = default;
36 
37  [[nodiscard]] static outcome::result<
38  std::unique_ptr<PolkadotTrieCursorImpl>>
40  const std::shared_ptr<const PolkadotTrie> &trie);
41 
42  [[nodiscard]] outcome::result<bool> seekFirst() override;
43 
44  [[nodiscard]] outcome::result<bool> seek(
45  const common::BufferView &key) override;
46 
47  [[nodiscard]] outcome::result<bool> seekLast() override;
48 
52  [[nodiscard]] outcome::result<void> seekLowerBound(
53  const common::BufferView &key) override;
54 
58  [[nodiscard]] outcome::result<void> seekUpperBound(
59  const common::BufferView &key) override;
60 
61  [[nodiscard]] bool isValid() const override;
62 
63  [[nodiscard]] outcome::result<void> next() override;
64 
65  [[nodiscard]] std::optional<common::Buffer> key() const override;
66 
67  [[nodiscard]] std::optional<common::BufferConstRef> value() const override;
68 
69  private:
70  outcome::result<void> seekLowerBoundInternal(
71  const TrieNode &current, gsl::span<const uint8_t> left_nibbles);
72  outcome::result<bool> nextNodeWithValueInOuterTree();
73  outcome::result<void> nextNodeWithValueInSubTree(
74  const TrieNode &subtree_root);
75  outcome::result<const TrieNode *> visitChildWithMinIdx(const TrieNode &node,
76  uint8_t min_idx = 0);
77 
82  struct TriePathEntry {
83  TriePathEntry(const BranchNode &parent, uint8_t child_idx)
84  : parent{parent}, child_idx{child_idx} {}
85 
87  uint8_t child_idx;
88  };
89 
90  class SearchState {
91  public:
92  explicit SearchState(const TrieNode &root) : current_{&root} {}
93 
94  SearchState(SearchState &&state) noexcept
95  : current_{state.current_}, path_{std::move(state.path_)} {}
96 
97  SearchState &operator=(SearchState &&state) noexcept {
98  current_ = state.current_;
99  path_ = std::move(state.path_);
100  return *this;
101  }
102 
103  SearchState(const SearchState &state) = delete;
104  SearchState &operator=(const SearchState &state) = delete;
105 
106  ~SearchState() = default;
107 
108  // need to pass child because of DummyNode logic (cannot obtain child
109  // directly, need to call retrieveChild of PolkadotTrie)
110  [[nodiscard]] outcome::result<void> visitChild(uint8_t index,
111  const TrieNode &child);
112 
113  [[nodiscard]] bool leaveChild() {
114  if (isAtRoot()) return false;
115  current_ = &path_.back().parent;
116  path_.pop_back();
117  return true;
118  }
119 
120  bool isAtRoot() const {
121  return path_.empty();
122  }
123 
124  const TrieNode &getCurrent() const {
125  BOOST_ASSERT_MSG(current_ != nullptr,
126  "SearchState implementation should guarantee it");
127  return *current_;
128  }
129 
130  std::vector<TriePathEntry> const &getPath() const {
131  return path_;
132  }
133 
134  private:
136  std::vector<TriePathEntry> path_; // from root to current
137  };
138 
139  // cursor state was invalidated and not restored
140  struct InvalidState {
141  std::error_code code;
142  };
143 
144  // cursor was created but no seek was performed
146 
147  struct ReachedEndState {};
148 
153  auto makeSearchStateAt(const common::BufferView &key)
154  -> outcome::result<SearchState>;
155 
156  common::Buffer collectKey() const;
157 
160 
161  template <typename Res>
162  outcome::result<Res> safeAccess(outcome::result<Res> &&result) {
163  if (result.has_error()) {
164  state_ = InvalidState{result.error()};
165  }
166  return std::move(result);
167  }
168 #define SAFE_VOID_CALL(expr) OUTCOME_TRY(safeAccess((expr)));
169 
170 #define SAFE_CALL(res, expr) OUTCOME_TRY(res, safeAccess((expr)));
171 
172  std::shared_ptr<const PolkadotTrie> trie_;
173 
174  using CursorState = std::
175  variant<UninitializedState, SearchState, InvalidState, ReachedEndState>;
177  };
178 
179 } // namespace kagome::storage::trie
180 
182 
183 #endif // KAGOME_CORE_STORAGE_TRIE_POLKADOT_TRIE_POLKADOT_TRIE_CURSOR_IMPL
uint8_t child_idx
Class represents arbitrary (including empty) byte buffer.
Definition: buffer.hpp:29
std::variant< UninitializedState, SearchState, InvalidState, ReachedEndState > CursorState
outcome::result< void > seekLowerBoundInternal(const TrieNode &current, gsl::span< const uint8_t > left_nibbles)
outcome::result< bool > seekFirst() override
Same as std::begin(...);.
auto makeSearchStateAt(const common::BufferView &key) -> outcome::result< SearchState >
outcome::result< void > nextNodeWithValueInSubTree(const TrieNode &subtree_root)
outcome::result< void > seekLowerBound(const common::BufferView &key) override
outcome::result< Res > safeAccess(outcome::result< Res > &&result)
OUTCOME_HPP_DECLARE_ERROR(kagome::api, JRpcServerImpl::Error)
outcome::result< bool > seek(const common::BufferView &key) override
Find given key and seek iterator to this key.
std::shared_ptr< soralog::Logger > Logger
Definition: logger.hpp:23
outcome::result< void > seekUpperBound(const common::BufferView &key) override
outcome::result< bool > seekLast() override
Same as std::rbegin(...);, e.g. points to the last valid element.
PolkadotTrieCursorImpl(std::shared_ptr< const PolkadotTrie > trie)
bool isValid() const override
Is the cursor in a valid state?
const BranchNode & parent
outcome::result< const TrieNode * > visitChildWithMinIdx(const TrieNode &node, uint8_t min_idx=0)
TriePathEntry(const BranchNode &parent, uint8_t child_idx)
std::optional< common::BufferConstRef > value() const override
Getter for value of the element currently pointed at.
static outcome::result< std::unique_ptr< PolkadotTrieCursorImpl > > createAt(const common::BufferView &key, const std::shared_ptr< const PolkadotTrie > &trie)
outcome::result< void > next() override
Make step forward.
std::optional< common::Buffer > key() const override
Getter for the key of the element currently pointed at.