#include #include namespace ripple { namespace detail { class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base { private: std::shared_ptr sle0_; ReadView::sles_type::iterator iter0_; ReadView::sles_type::iterator end0_; std::shared_ptr sle1_; items_t::const_iterator iter1_; items_t::const_iterator end1_; public: sles_iter_impl(sles_iter_impl const&) = default; sles_iter_impl( items_t::const_iterator iter1, items_t::const_iterator end1, ReadView::sles_type::iterator iter0, ReadView::sles_type::iterator end0) : iter0_(iter0), end0_(end0), iter1_(iter1), end1_(end1) { if (iter0_ != end0_) sle0_ = *iter0_; if (iter1_ != end1) { sle1_ = iter1_->second.sle; skip(); } } std::unique_ptr copy() const override { return std::make_unique(*this); } bool equal(base_type const& impl) const override { if (auto const p = dynamic_cast(&impl)) { XRPL_ASSERT( end1_ == p->end1_ && end0_ == p->end0_, "ripple::detail::RawStateTable::equal : matching end " "iterators"); return iter1_ == p->iter1_ && iter0_ == p->iter0_; } return false; } void increment() override { XRPL_ASSERT( sle1_ || sle0_, "ripple::detail::RawStateTable::increment : either SLE is " "non-null"); if (sle1_ && !sle0_) { inc1(); return; } if (sle0_ && !sle1_) { inc0(); return; } if (sle1_->key() == sle0_->key()) { inc1(); inc0(); } else if (sle1_->key() < sle0_->key()) { inc1(); } else { inc0(); } skip(); } value_type dereference() const override { if (!sle1_) return sle0_; else if (!sle0_) return sle1_; if (sle1_->key() <= sle0_->key()) return sle1_; return sle0_; } private: void inc0() { ++iter0_; if (iter0_ == end0_) sle0_ = nullptr; else sle0_ = *iter0_; } void inc1() { ++iter1_; if (iter1_ == end1_) sle1_ = nullptr; else sle1_ = iter1_->second.sle; } void skip() { while (iter1_ != end1_ && iter1_->second.action == Action::erase && sle0_->key() == sle1_->key()) { inc1(); inc0(); if (!sle0_) return; } } }; //------------------------------------------------------------------------------ // Base invariants are checked by the base during apply() void RawStateTable::apply(RawView& to) const { to.rawDestroyXRP(dropsDestroyed_); for (auto const& elem : items_) { auto const& item = elem.second; switch (item.action) { case Action::erase: to.rawErase(item.sle); break; case Action::insert: to.rawInsert(item.sle); break; case Action::replace: to.rawReplace(item.sle); break; } } } bool RawStateTable::exists(ReadView const& base, Keylet const& k) const { XRPL_ASSERT( k.key.isNonZero(), "ripple::detail::RawStateTable::exists : nonzero key"); auto const iter = items_.find(k.key); if (iter == items_.end()) return base.exists(k); auto const& item = iter->second; if (item.action == Action::erase) return false; if (!k.check(*item.sle)) return false; return true; } /* This works by first calculating succ() on the parent, then calculating succ() our internal list, and taking the lower of the two. */ auto RawStateTable::succ( ReadView const& base, key_type const& key, std::optional const& last) const -> std::optional { std::optional next = key; items_t::const_iterator iter; // Find base successor that is // not also deleted in our list do { next = base.succ(*next, last); if (!next) break; iter = items_.find(*next); } while (iter != items_.end() && iter->second.action == Action::erase); // Find non-deleted successor in our list for (iter = items_.upper_bound(key); iter != items_.end(); ++iter) { if (iter->second.action != Action::erase) { // Found both, return the lower key if (!next || next > iter->first) next = iter->first; break; } } // Nothing in our list, return // what we got from the parent. if (last && next >= last) return std::nullopt; return next; } void RawStateTable::erase(std::shared_ptr const& sle) { // The base invariant is checked during apply auto const result = items_.emplace( std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::erase, sle)); if (result.second) return; auto& item = result.first->second; switch (item.action) { case Action::erase: LogicError("RawStateTable::erase: already erased"); break; case Action::insert: items_.erase(result.first); break; case Action::replace: item.action = Action::erase; item.sle = sle; break; } } void RawStateTable::insert(std::shared_ptr const& sle) { auto const result = items_.emplace( std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::insert, sle)); if (result.second) return; auto& item = result.first->second; switch (item.action) { case Action::erase: item.action = Action::replace; item.sle = sle; break; case Action::insert: LogicError("RawStateTable::insert: already inserted"); break; case Action::replace: LogicError("RawStateTable::insert: already exists"); break; } } void RawStateTable::replace(std::shared_ptr const& sle) { auto const result = items_.emplace( std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::replace, sle)); if (result.second) return; auto& item = result.first->second; switch (item.action) { case Action::erase: LogicError("RawStateTable::replace: was erased"); break; case Action::insert: case Action::replace: item.sle = sle; break; } } std::shared_ptr RawStateTable::read(ReadView const& base, Keylet const& k) const { auto const iter = items_.find(k.key); if (iter == items_.end()) return base.read(k); auto const& item = iter->second; if (item.action == Action::erase) return nullptr; // Convert to SLE const std::shared_ptr sle = item.sle; if (!k.check(*sle)) return nullptr; return sle; } void RawStateTable::destroyXRP(XRPAmount const& fee) { dropsDestroyed_ += fee; } std::unique_ptr RawStateTable::slesBegin(ReadView const& base) const { return std::make_unique( items_.begin(), items_.end(), base.sles.begin(), base.sles.end()); } std::unique_ptr RawStateTable::slesEnd(ReadView const& base) const { return std::make_unique( items_.end(), items_.end(), base.sles.end(), base.sles.end()); } std::unique_ptr RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const { return std::make_unique( items_.upper_bound(key), items_.end(), base.sles.upper_bound(key), base.sles.end()); } } // namespace detail } // namespace ripple