diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj index f5907cca31..45c6727218 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj +++ b/Builds/VisualStudio2015/RippleD.vcxproj @@ -2295,6 +2295,8 @@ + + @@ -2323,6 +2325,10 @@ True True + + True + True + True True @@ -2369,6 +2375,10 @@ + + True + True + True True diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters index e1bb737a57..05386ba033 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters @@ -3018,6 +3018,9 @@ ripple\ledger + + ripple\ledger + ripple\ledger @@ -3051,6 +3054,9 @@ ripple\ledger\impl + + ripple\ledger\impl + ripple\ledger\impl @@ -3093,6 +3099,9 @@ ripple\ledger + + ripple\ledger\tests + ripple\ledger\tests diff --git a/src/ripple/ledger/BookDirs.h b/src/ripple/ledger/BookDirs.h new file mode 100644 index 0000000000..ddf3eebdba --- /dev/null +++ b/src/ripple/ledger/BookDirs.h @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED +#define RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED + +#include + +namespace ripple { + +class BookDirs +{ +private: + ReadView const* view_ = nullptr; + uint256 const root_; + uint256 const next_quality_; + uint256 const key_; + std::shared_ptr sle_ = nullptr; + unsigned int entry_ = 0; + uint256 index_; + +public: + class const_iterator; + using value_type = std::shared_ptr; + + BookDirs(ReadView const&, Book const&); + + const_iterator + begin() const; + + const_iterator + end() const; +}; + +class BookDirs::const_iterator +{ +public: + using value_type = + BookDirs::value_type; + using pointer = + value_type const*; + using reference = + value_type const&; + using difference_type = + std::ptrdiff_t; + using iterator_category = + std::forward_iterator_tag; + + const_iterator() = default; + + bool + operator==(const_iterator const& other) const; + + bool + operator!=(const_iterator const& other) const + { + return ! (*this == other); + } + + reference + operator*() const; + + pointer + operator->() const + { + return &**this; + } + + const_iterator& + operator++(); + + const_iterator + operator++(int); + +private: + friend class BookDirs; + + const_iterator(ReadView const& view, + uint256 const& root, uint256 const& dir_key) + : view_(&view) + , root_(root) + , key_(dir_key) + , cur_key_(dir_key) + { + } + + ReadView const* view_ = nullptr; + uint256 root_; + uint256 next_quality_; + uint256 key_; + uint256 cur_key_; + std::shared_ptr sle_; + unsigned int entry_ = 0; + uint256 index_; + boost::optional mutable cache_; + + static beast::Journal j_; +}; + +} // ripple + +#endif diff --git a/src/ripple/ledger/Directory.h b/src/ripple/ledger/Directory.h index 118677c4dd..e2a1a381e7 100644 --- a/src/ripple/ledger/Directory.h +++ b/src/ripple/ledger/Directory.h @@ -30,8 +30,6 @@ class Dir private: ReadView const* view_ = nullptr; Keylet root_; - - // memoization std::shared_ptr sle_; STVector256 const* indexes_ = nullptr; @@ -67,9 +65,6 @@ public: const_iterator() = default; - const_iterator& - operator=(const_iterator const& other); - bool operator==(const_iterator const& other) const; @@ -110,8 +105,7 @@ private: friend class Dir; const_iterator(ReadView const& view, - Keylet const& root, - Keylet const& page) + Keylet const& root, Keylet const& page) : view_(&view) , root_(root) , page_(page) @@ -123,8 +117,6 @@ private: Keylet page_; uint256 index_; boost::optional mutable cache_; - - // memoization std::shared_ptr sle_; STVector256 const* indexes_ = nullptr; std::vector::const_iterator it_; diff --git a/src/ripple/ledger/impl/BookDirs.cpp b/src/ripple/ledger/impl/BookDirs.cpp new file mode 100644 index 0000000000..49cdbb1cd6 --- /dev/null +++ b/src/ripple/ledger/impl/BookDirs.cpp @@ -0,0 +1,125 @@ +//------------ ------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include + +namespace ripple { + +BookDirs::BookDirs(ReadView const& view, Book const& book) + : view_(&view) + , root_(keylet::page(getBookBase(book)).key) + , next_quality_(getQualityNext(root_)) + , key_(view_->succ(root_, next_quality_).value_or(zero)) +{ + assert(root_ != zero); + if (key_ != zero) + { + if (! cdirFirst(*view_, key_, sle_, entry_, index_, + beast::Journal())) + { + assert(false); + } + } +} + +auto +BookDirs::begin() const -> + BookDirs::const_iterator +{ + auto it = BookDirs::const_iterator(*view_, root_, key_); + if (key_ != zero) + { + it.next_quality_ = next_quality_; + it.sle_ = sle_; + it.entry_ = entry_; + it.index_ = index_; + } + return it; +} + +auto +BookDirs::end() const -> + BookDirs::const_iterator +{ + return BookDirs::const_iterator(*view_, root_, key_); +} + + +beast::Journal BookDirs::const_iterator::j_ = beast::Journal(); + +bool +BookDirs::const_iterator::operator== + (BookDirs::const_iterator const& other) const +{ + if (view_ == nullptr || other.view_ == nullptr) + return false; + + assert(view_ == other.view_ && root_ == other.root_); + return entry_ == other.entry_ && + cur_key_ == other.cur_key_ && + index_ == other.index_; +} + +BookDirs::const_iterator::reference +BookDirs::const_iterator::operator*() const +{ + assert(index_ != zero); + if (! cache_) + cache_ = view_->read(keylet::offer(index_)); + return *cache_; +} + +BookDirs::const_iterator& +BookDirs::const_iterator::operator++() +{ + assert(index_ != zero); + if (! cdirNext(*view_, cur_key_, sle_, entry_, index_, j_)) + { + if (index_ != 0 || + (cur_key_ = view_->succ(++cur_key_, + next_quality_).value_or(zero)) == zero) + { + cur_key_ = key_; + entry_ = 0; + index_ = zero; + } + else if (! cdirFirst(*view_, cur_key_, + sle_, entry_, index_, j_)) + { + assert(false); + } + } + + cache_ = boost::none; + return *this; +} + +BookDirs::const_iterator +BookDirs::const_iterator::operator++(int) +{ + assert(index_ != zero); + const_iterator tmp(*this); + ++(*this); + return tmp; +} + +} // ripple diff --git a/src/ripple/ledger/impl/Directory.cpp b/src/ripple/ledger/impl/Directory.cpp index aa4590109f..b52738336f 100644 --- a/src/ripple/ledger/impl/Directory.cpp +++ b/src/ripple/ledger/impl/Directory.cpp @@ -29,7 +29,6 @@ Dir::Dir(ReadView const& view, : view_(&view) , root_(key) , sle_(view_->read(root_)) - { if (sle_ != nullptr) indexes_ = &sle_->getFieldV256(sfIndexes); @@ -77,7 +76,10 @@ Dir::find(uint256 const& page_key, uint256 const& sle_key) const { it.sle_ = view_->read(it.page_); if (it.sle_ == nullptr) - return end(); + { + it.page_ = root_; + return it; + } it.indexes_ = &it.sle_->getFieldV256(sfIndexes); } @@ -90,23 +92,6 @@ Dir::find(uint256 const& page_key, uint256 const& sle_key) const return it; } -const_iterator& -const_iterator::operator=(const_iterator const& other) -{ - if (this != &other) - { - view_ = other.view_; - root_ = other.root_; - page_ = other.page_; - index_ = other.index_; - cache_ = other.cache_; - sle_ = other.sle_; - indexes_ = other.indexes_; - it_ = other.it_; - } - return *this; -} - bool const_iterator::operator==(const_iterator const& other) const { @@ -120,7 +105,7 @@ const_iterator::operator==(const_iterator const& other) const const_iterator::reference const_iterator::operator*() const { - assert(index_ != beast::zero); + assert(index_ != zero); if (! cache_) cache_ = view_->read(keylet::child(index_)); return *cache_; @@ -129,7 +114,7 @@ const_iterator::operator*() const const_iterator& const_iterator::operator++() { - assert(index_ != beast::zero); + assert(index_ != zero); if (++it_ != std::end(*indexes_)) { index_ = *it_; @@ -141,7 +126,7 @@ const_iterator::operator++() if (next == 0) { page_.key = root_.key; - index_ = beast::zero; + index_ = zero; } else { @@ -151,7 +136,7 @@ const_iterator::operator++() indexes_ = &sle_->getFieldV256(sfIndexes); if (indexes_->empty()) { - index_ = beast::zero; + index_ = zero; } else { @@ -168,7 +153,7 @@ const_iterator::operator++() const_iterator const_iterator::operator++(int) { - assert(index_ != beast::zero); + assert(index_ != zero); const_iterator tmp(*this); ++(*this); return tmp; diff --git a/src/ripple/ledger/tests/BookDirs_test.cpp b/src/ripple/ledger/tests/BookDirs_test.cpp new file mode 100644 index 0000000000..be76afa4f1 --- /dev/null +++ b/src/ripple/ledger/tests/BookDirs_test.cpp @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +namespace ripple { +namespace test { + +struct BookDirs_test : public beast::unit_test::suite +{ + void test_bookdir() + { + using namespace jtx; + Env env(*this); + auto gw = Account("gw"); + auto USD = gw["USD"]; + env.fund(XRP(1000000), "alice", "bob", "gw"); + + { + Book book(xrpIssue(), USD.issue()); + { + auto d = BookDirs(*env.open(), book); + expect(std::begin(d) == std::end(d)); + expect(std::distance(d.begin(), d.end()) == 0); + } + { + auto d = BookDirs(*env.open(), reversed(book)); + expect(std::distance(d.begin(), d.end()) == 0); + } + } + + { + env(offer("alice", Account("alice")["USD"](50), XRP(10))); + auto d = BookDirs(*env.open(), + Book(Account("alice")["USD"].issue(), xrpIssue())); + expect(std::distance(d.begin(), d.end()) == 1); + } + + { + env(offer("alice", gw["CNY"](50), XRP(10))); + auto d = BookDirs(*env.open(), + Book(gw["CNY"].issue(), xrpIssue())); + expect(std::distance(d.begin(), d.end()) == 1); + } + + { + env.trust(Account("bob")["CNY"](10), "alice"); + env(pay("bob", "alice", Account("bob")["CNY"](10))); + env(offer("alice", USD(50), Account("bob")["CNY"](10))); + auto d = BookDirs(*env.open(), + Book(USD.issue(), Account("bob")["CNY"].issue())); + expect(std::distance(d.begin(), d.end()) == 1); + } + + { + auto AUD = gw["AUD"]; + for (auto i = 1, j = 3; i <= 3; ++i, --j) + for (auto k = 0; k < 80; ++k) + env(offer("alice", AUD(i), XRP(j))); + + auto d = BookDirs(*env.open(), + Book(AUD.issue(), xrpIssue())); + expect(std::distance(d.begin(), d.end()) == 240); + auto i = 1, j = 3, k = 0; + for (auto const& e : d) + { + expect(e->getFieldAmount(sfTakerPays) == AUD(i)); + expect(e->getFieldAmount(sfTakerGets) == XRP(j)); + if (++k % 80 == 0) + { + ++i; + --j; + } + } + } + } + + void run() override + { + test_bookdir(); + } +}; + +BEAST_DEFINE_TESTSUITE(BookDirs,ledger,ripple); + +} // test +} // ripple diff --git a/src/ripple/unity/ledger.cpp b/src/ripple/unity/ledger.cpp index 3d3422c206..fa09ddde93 100644 --- a/src/ripple/unity/ledger.cpp +++ b/src/ripple/unity/ledger.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include +#include #include #include #include