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