diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj index 20dd9bceb76..8b8e1a64274 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj +++ b/Builds/VisualStudio2015/RippleD.vcxproj @@ -1431,10 +1431,6 @@ True True - - True - True - True True diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters index 03fc1ae808b..5d4a2e8b81a 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters @@ -1959,9 +1959,6 @@ ripple\basics\impl - - ripple\basics\impl - ripple\basics\impl diff --git a/src/ripple/app/ledger/LedgerMaster.h b/src/ripple/app/ledger/LedgerMaster.h index d3217073c05..21006d361ea 100644 --- a/src/ripple/app/ledger/LedgerMaster.h +++ b/src/ripple/app/ledger/LedgerMaster.h @@ -305,7 +305,7 @@ class LedgerMaster std::unique_ptr replayData; std::recursive_mutex mCompleteLock; - RangeSet mCompleteLedgers; + RangeSet mCompleteLedgers; std::unique_ptr mLedgerCleaner; diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index 6814c1d2e76..4b48a2a7d11 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -344,14 +344,14 @@ bool LedgerMaster::haveLedger (std::uint32_t seq) { ScopedLockType sl (mCompleteLock); - return mCompleteLedgers.hasValue (seq); + return boost::icl::contains(mCompleteLedgers, seq); } void LedgerMaster::clearLedger (std::uint32_t seq) { ScopedLockType sl (mCompleteLock); - return mCompleteLedgers.clearValue (seq); + mCompleteLedgers.erase (seq); } // returns Ledgers we have all the nodes for @@ -365,15 +365,16 @@ LedgerMaster::getFullValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVa if (!maxVal) return false; + boost::optional maybeMin; { ScopedLockType sl (mCompleteLock); - minVal = mCompleteLedgers.prevMissing (maxVal); + maybeMin = prevMissing(mCompleteLedgers, maxVal); } - if (minVal == RangeSet::absent) + if (maybeMin == boost::none) minVal = maxVal; else - ++minVal; + minVal = 1 + *maybeMin; return true; } @@ -382,23 +383,9 @@ LedgerMaster::getFullValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVa bool LedgerMaster::getValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal) { - // Validated ledger is likely not stored in the DB yet so we use the - // published ledger which is. - maxVal = mPubLedgerSeq.load(); - - if (!maxVal) + if (!getFullValidatedRange(minVal, maxVal)) return false; - { - ScopedLockType sl (mCompleteLock); - minVal = mCompleteLedgers.prevMissing (maxVal); - } - - if (minVal == RangeSet::absent) - minVal = maxVal; - else - ++minVal; - // Remove from the validated range any ledger sequences that may not be // fully updated in the database yet @@ -481,8 +468,8 @@ LedgerMaster::tryFill ( return; { - ScopedLockType ml (mCompleteLock); - mCompleteLedgers.setRange (minHas, maxHas); + ScopedLockType ml(mCompleteLock); + mCompleteLedgers.insert(range(minHas, maxHas)); } maxHas = minHas; ledgerHashes = getHashesByIndex ((seq < 500) @@ -502,7 +489,7 @@ LedgerMaster::tryFill ( { ScopedLockType ml (mCompleteLock); - mCompleteLedgers.setRange (minHas, maxHas); + mCompleteLedgers.insert(range(minHas, maxHas)); } { ScopedLockType ml (m_mutex); @@ -647,7 +634,7 @@ LedgerMaster::setFullLedger ( { ScopedLockType ml (mCompleteLock); - mCompleteLedgers.setValue (ledger->info().seq); + mCompleteLedgers.insert (ledger->info().seq); } { @@ -1283,7 +1270,7 @@ std::string LedgerMaster::getCompleteLedgers () { ScopedLockType sl (mCompleteLock); - return mCompleteLedgers.toString (); + return to_string(mCompleteLedgers); } boost::optional @@ -1447,7 +1434,7 @@ void LedgerMaster::setLedgerRangePresent (std::uint32_t minV, std::uint32_t maxV) { ScopedLockType sl (mCompleteLock); - mCompleteLedgers.setRange (minV, maxV); + mCompleteLedgers.insert(range(minV, maxV)); } void @@ -1478,12 +1465,9 @@ LedgerMaster::getPropertySource () void LedgerMaster::clearPriorLedgers (LedgerIndex seq) { - ScopedLockType sl (mCompleteLock); - for (LedgerIndex i = mCompleteLedgers.getFirst(); i < seq; ++i) - { - if (haveLedger (i)) - clearLedger (i); - } + ScopedLockType sl(mCompleteLock); + if (seq > 0) + mCompleteLedgers.erase(range(0u, seq - 1)); } void @@ -1547,137 +1531,141 @@ void LedgerMaster::doAdvance () (mValidLedgerSeq == mPubLedgerSeq) && (getValidatedLedgerAge() < MAX_LEDGER_AGE_ACQUIRE)) { // We are in sync, so can acquire - std::uint32_t missing; + boost::optional maybeMissing; { ScopedLockType sl (mCompleteLock); - missing = mCompleteLedgers.prevMissing( - mPubLedger->info().seq); + maybeMissing = + prevMissing(mCompleteLedgers, mPubLedger->info().seq); } - JLOG (m_journal.trace()) - << "tryAdvance discovered missing " << missing; - if ((missing != RangeSet::absent) && (missing > 0) && - shouldAcquire (mValidLedgerSeq, ledger_history_, - app_.getSHAMapStore ().getCanDelete (), missing) && - ((mFillInProgress == 0) || (missing > mFillInProgress))) + if (maybeMissing) { - JLOG (m_journal.trace()) - << "advanceThread should acquire"; + std::uint32_t missing = *maybeMissing; + JLOG(m_journal.trace()) + << "tryAdvance discovered missing " << missing; + if ((missing > 0) && + shouldAcquire(mValidLedgerSeq, ledger_history_, + app_.getSHAMapStore().getCanDelete(), missing) && + ((mFillInProgress == 0) || (missing > mFillInProgress))) { - ScopedUnlockType sl(m_mutex); - auto hash = getLedgerHashForHistory (missing); - if (hash) + JLOG(m_journal.trace()) + << "advanceThread should acquire"; { - assert(hash->isNonZero()); - auto ledger = getLedgerByHash (*hash); - if (!ledger) + ScopedUnlockType sl(m_mutex); + auto hash = getLedgerHashForHistory(missing); + if (hash) { - if (!app_.getInboundLedgers().isFailure ( - *hash)) + assert(hash->isNonZero()); + auto ledger = getLedgerByHash(*hash); + if (!ledger) { - ledger = - app_.getInboundLedgers().acquire( - *hash, missing, - InboundLedger::fcHISTORY); - if (! ledger && (missing > 32600) && - shouldFetchPack (missing)) + if (!app_.getInboundLedgers().isFailure( + *hash)) { - JLOG (m_journal.trace()) << - "tryAdvance want fetch pack " << - missing; - fetch_seq_ = missing; - getFetchPack(*hash, missing); + ledger = + app_.getInboundLedgers().acquire( + *hash, missing, + InboundLedger::fcHISTORY); + if (!ledger && (missing > 32600) && + shouldFetchPack(missing)) + { + JLOG(m_journal.trace()) << + "tryAdvance want fetch pack " << + missing; + fetch_seq_ = missing; + getFetchPack(*hash, missing); + } + else + JLOG(m_journal.trace()) << + "tryAdvance no fetch pack for " << + missing; } else - JLOG (m_journal.trace()) << - "tryAdvance no fetch pack for " << - missing; + JLOG(m_journal.debug()) << + "tryAdvance found failed acquire"; } - else - JLOG (m_journal.debug()) << - "tryAdvance found failed acquire"; - } - if (ledger) - { - auto seq = ledger->info().seq; - assert(seq == missing); - JLOG (m_journal.trace()) + if (ledger) + { + auto seq = ledger->info().seq; + assert(seq == missing); + JLOG(m_journal.trace()) << "tryAdvance acquired " << ledger->info().seq; - setFullLedger( - ledger, - false, - false); - auto const& parent = ledger->info().parentHash; - - int fillInProgress; - { - ScopedLockType lock(m_mutex); - mHistLedger = ledger; - fillInProgress = mFillInProgress; - } + setFullLedger( + ledger, + false, + false); + auto const& parent = ledger->info().parentHash; - if (fillInProgress == 0 && - getHashByIndex(seq - 1, app_) == parent) - { + int fillInProgress; { - // Previous ledger is in DB ScopedLockType lock(m_mutex); - mFillInProgress = ledger->info().seq; + mHistLedger = ledger; + fillInProgress = mFillInProgress; } - app_.getJobQueue().addJob( - jtADVANCE, "tryFill", - [this, ledger] (Job& j) { + if (fillInProgress == 0 && + getHashByIndex(seq - 1, app_) == parent) + { + { + // Previous ledger is in DB + ScopedLockType lock(m_mutex); + mFillInProgress = ledger->info().seq; + } + + app_.getJobQueue().addJob( + jtADVANCE, "tryFill", + [this, ledger](Job& j) { tryFill(j, ledger); }); - } + } - progress = true; - } - else - { - try + progress = true; + } + else { - for (int i = 0; i < ledger_fetch_size_; ++i) + try { - std::uint32_t seq = missing - i; - auto hash2 = - getLedgerHashForHistory(seq); - if (hash2) + for (int i = 0; i < ledger_fetch_size_; ++i) { - assert(hash2->isNonZero()); - app_.getInboundLedgers().acquire + std::uint32_t seq = missing - i; + auto hash2 = + getLedgerHashForHistory(seq); + if (hash2) + { + assert(hash2->isNonZero()); + app_.getInboundLedgers().acquire (*hash2, seq, InboundLedger::fcHISTORY); + } } } - } - catch (std::exception const&) - { - JLOG (m_journal.warn()) << - "Threw while prefetching"; + catch (std::exception const&) + { + JLOG(m_journal.warn()) << + "Threw while prefetching"; + } } } + else + { + JLOG(m_journal.fatal()) << + "Can't find ledger following prevMissing " << + missing; + JLOG(m_journal.fatal()) << "Pub:" << + mPubLedgerSeq << " Val:" << mValidLedgerSeq; + JLOG(m_journal.fatal()) << "Ledgers: " << + app_.getLedgerMaster().getCompleteLedgers(); + clearLedger(missing + 1); + progress = true; + } } - else + if (mValidLedgerSeq != mPubLedgerSeq) { - JLOG (m_journal.fatal()) << - "Can't find ledger following prevMissing " << - missing; - JLOG (m_journal.fatal()) << "Pub:" << - mPubLedgerSeq << " Val:" << mValidLedgerSeq; - JLOG (m_journal.fatal()) << "Ledgers: " << - app_.getLedgerMaster().getCompleteLedgers(); - clearLedger (missing + 1); + JLOG(m_journal.debug()) << + "tryAdvance found last valid changed"; progress = true; } } - if (mValidLedgerSeq != mPubLedgerSeq) - { - JLOG (m_journal.debug()) << - "tryAdvance found last valid changed"; - progress = true; - } } } else diff --git a/src/ripple/basics/RangeSet.h b/src/ripple/basics/RangeSet.h index fbbaf5677b5..16b29bd182a 100644 --- a/src/ripple/basics/RangeSet.h +++ b/src/ripple/basics/RangeSet.h @@ -20,72 +20,113 @@ #ifndef RIPPLE_BASICS_RANGESET_H_INCLUDED #define RIPPLE_BASICS_RANGESET_H_INCLUDED -#include -#include #include +#include +#include +#include -namespace ripple { - -/** A sparse set of integers. */ -// VFALCO TODO Replace with juce::SparseSet -class RangeSet +namespace ripple { -public: - static const std::uint32_t absent = static_cast (-1); -public: - RangeSet () { } +/** A closed interval over the domain T. - bool hasValue (std::uint32_t) const; + For an instance ClosedInterval c, this represents the closed interval + (c.first(), c.last()). A single element interval has c.first() == c.last(). - std::uint32_t getFirst () const; - std::uint32_t getNext (std::uint32_t) const; - std::uint32_t getLast () const; - std::uint32_t getPrev (std::uint32_t) const; + This is simply a type-alias for boost interval container library interval + set, so users should consult that documentation for available supporting + member and free functions. +*/ +template +using ClosedInterval = boost::icl::closed_interval; - // largest number not in the set that is less than the given number - std::uint32_t prevMissing (std::uint32_t) const; +/** Create a closed range interval - // Add an item to the set - void setValue (std::uint32_t); + Helper function to create a closed range interval without having to qualify + the template argument. +*/ +template +ClosedInterval +range(T low, T high) +{ + return ClosedInterval(low, high); +} - // Add the closed interval to the set - void setRange (std::uint32_t, std::uint32_t); +/** A set of closed intervals over the domain T. - void clearValue (std::uint32_t); + Represents a set of values of the domain T using the minimum number + of disjoint ClosedInterval. This is useful to represent ranges of + T where a few instances are missing, e.g. the set 1-5,8-9,11-14. - std::string toString () const; + This is simply a type-alias for boost interval container library interval + set, so users should consult that documentation for available supporting + member and free functions. +*/ +template +using RangeSet = boost::icl::interval_set>; - /** Returns the sum of the Lebesgue measures of all sub-ranges. */ - std::size_t - lebesgue_sum() const; - /** Check invariants of the data. +/** Convert a ClosedInterval to a styled string - This is for diagnostics, and does nothing in release builds. - */ - void checkInternalConsistency () const noexcept; + The styled string is + "c.first()-c.last()" if c.first() != c.last() + "c.first()" if c.first() == c.last() -private: - void simplify (); + @param ci The closed interval to convert + @return The style string +*/ +template +std::string to_string(ClosedInterval const & ci) +{ + if (ci.first() == ci.last()) + return std::to_string(ci.first()); + return std::to_string(ci.first()) + "-" + std::to_string(ci.last()); +} -private: - using Map = std::map ; +/** Convert the given RangeSet to a styled string. - using const_iterator = Map::const_iterator; - using const_reverse_iterator = Map::const_reverse_iterator; - using value_type = Map::value_type; - using iterator = Map::iterator; + The styled string represention is the set of disjoint intervals joined by + commas. The string "empty" is returned if the set is empty. - static bool contains (value_type const& it, std::uint32_t v) + @param rs The rangeset to convert + @return The styled string +*/ +template +std::string to_string(RangeSet const & rs) +{ + using ripple::to_string; + + if (rs.empty()) + return "empty"; + std::string res = ""; + for (auto const & interval : rs) { - return (it.first <= v) && (it.second >= v); + if (!res.empty()) + res += ","; + res += to_string(interval); } + return res; +} - // First is lowest value in range, last is highest value in range - Map mRanges; -}; - -} // ripple +/** Find the largest value not in the set that is less than a given value. + @param rs The set of interest + @param t The value that must be larger than the result + @param minVal (Default is 0) The smallest allowed value + @return The largest v such that minV <= v < t and !contains(rs, v) or + boost::none if no such v exists. +*/ +template +boost::optional +prevMissing(RangeSet const & rs, T t, T minVal = 0) +{ + if (rs.empty() || t == minVal) + return boost::none; + RangeSet tgt{ ClosedInterval{minVal, t - 1} }; + tgt -= rs; + if (tgt.empty()) + return boost::none; + return boost::icl::last(tgt); +} + } // namespace ripple #endif diff --git a/src/ripple/basics/impl/RangeSet.cpp b/src/ripple/basics/impl/RangeSet.cpp deleted file mode 100644 index ed13d5349e4..00000000000 --- a/src/ripple/basics/impl/RangeSet.cpp +++ /dev/null @@ -1,270 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include - -namespace ripple { - -// VFALCO NOTE std::min and std::max not good enough? -// NOTE Why isn't this written as a template? -// TODO Replace this with std calls. -// -inline std::uint32_t min (std::uint32_t x, std::uint32_t y) -{ - return (x < y) ? x : y; -} -inline std::uint32_t max (std::uint32_t x, std::uint32_t y) -{ - return (x > y) ? x : y; -} - -bool RangeSet::hasValue (std::uint32_t v) const -{ - for (auto const& it : mRanges) - { - if (contains (it, v)) - return true; - } - return false; -} - -std::uint32_t RangeSet::getFirst () const -{ - const_iterator it = mRanges.begin (); - - if (it == mRanges.end ()) - return absent; - - return it->first; -} - -std::uint32_t RangeSet::getNext (std::uint32_t v) const -{ - for (auto const& it : mRanges) - { - if (it.first > v) - return it.first; - - if (contains (it, v + 1)) - return v + 1; - } - return absent; -} - -std::uint32_t RangeSet::getLast () const -{ - const_reverse_iterator it = mRanges.rbegin (); - - if (it == mRanges.rend ()) - return absent; - - return it->second; -} - -std::uint32_t RangeSet::getPrev (std::uint32_t v) const -{ - BOOST_REVERSE_FOREACH (const value_type & it, mRanges) - { - if (it.second < v) - return it.second; - - if (contains (it, v + 1)) - return v - 1; - } - return absent; -} - -// Return the largest number not in the set that is less than the given number -// -std::uint32_t RangeSet::prevMissing (std::uint32_t v) const -{ - std::uint32_t result = absent; - - if (v != 0) - { - checkInternalConsistency (); - - // Handle the case where the loop reaches the terminating condition - // - result = v - 1; - - for (const_reverse_iterator cur = mRanges.rbegin (); cur != mRanges.rend (); ++cur) - { - // See if v-1 is in the range - if (contains (*cur, result)) - { - result = cur->first - 1; - break; - } - } - } - - assert (result == absent || !hasValue (result)); - - return result; -} - -void RangeSet::setValue (std::uint32_t v) -{ - if (!hasValue (v)) - { - mRanges[v] = v; - - simplify (); - } -} - -void RangeSet::setRange (std::uint32_t minV, std::uint32_t maxV) -{ - while (hasValue (minV)) - { - ++minV; - - if (minV >= maxV) - return; - } - - mRanges[minV] = maxV; - - simplify (); -} - -void RangeSet::clearValue (std::uint32_t v) -{ - for (iterator it = mRanges.begin (); it != mRanges.end (); ++it) - { - if (contains (*it, v)) - { - if (it->first == v) - { - if (it->second == v) - { - mRanges.erase (it); - } - else - { - std::uint32_t oldEnd = it->second; - mRanges.erase(it); - mRanges[v + 1] = oldEnd; - } - } - else if (it->second == v) - { - -- (it->second); - } - else - { - std::uint32_t oldEnd = it->second; - it->second = v - 1; - mRanges[v + 1] = oldEnd; - } - - checkInternalConsistency(); - return; - } - } -} - -std::string RangeSet::toString () const -{ - std::string ret; - for (auto const& it : mRanges) - { - if (!ret.empty ()) - ret += ","; - - if (it.first == it.second) - ret += beast::lexicalCastThrow ((it.first)); - else - ret += beast::lexicalCastThrow (it.first) + "-" - + beast::lexicalCastThrow (it.second); - } - - if (ret.empty ()) - return "empty"; - - return ret; -} - -void RangeSet::simplify () -{ - iterator it = mRanges.begin (); - - while (1) - { - iterator nit = it; - - if (++nit == mRanges.end ()) - { - checkInternalConsistency(); - return; - } - - if (it->second >= (nit->first - 1)) - { - // ranges overlap - it->second = std::max(it->second, nit->second); - mRanges.erase (nit); - } - else - { - it = nit; - } - } -} - -std::size_t -RangeSet::lebesgue_sum() const -{ - std::size_t sum = mRanges.size(); - for (auto const& e : mRanges) - sum += e.second - e.first; - return sum; -} - -void RangeSet::checkInternalConsistency () const noexcept -{ -#ifndef NDEBUG - if (mRanges.size () > 1) - { - const_iterator const last = std::prev (mRanges.end ()); - - for (const_iterator cur = mRanges.begin (); cur != last; ++cur) - { - const_iterator const next = std::next (cur); - assert (cur->first <= cur->second); - assert (next->first <= next->second); - assert (cur->second + 1 < next->first); - } - } - else if (mRanges.size () == 1) - { - const_iterator const iter = mRanges.begin (); - assert (iter->first <= iter->second); - } -#endif -} - -} // ripple diff --git a/src/ripple/unity/basics.cpp b/src/ripple/unity/basics.cpp index e24eab78d99..e15ed5faf96 100644 --- a/src/ripple/unity/basics.cpp +++ b/src/ripple/unity/basics.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/src/test/basics/RangeSet_test.cpp b/src/test/basics/RangeSet_test.cpp index e433a49a32f..ce12c4a240a 100644 --- a/src/test/basics/RangeSet_test.cpp +++ b/src/test/basics/RangeSet_test.cpp @@ -21,14 +21,15 @@ #include #include -namespace ripple { - +namespace ripple +{ class RangeSet_test : public beast::unit_test::suite { public: - RangeSet createPredefinedSet () + void + testPrevMissing() { - RangeSet set; + testcase("prevMissing"); // Set will include: // [ 0, 5] @@ -36,59 +37,52 @@ class RangeSet_test : public beast::unit_test::suite // [20,25] // etc... - for (int i = 0; i < 10; ++i) - set.setRange (10 * i, 10 * i + 5); + RangeSet set; + for (std::uint32_t i = 0; i < 10; ++i) + set.insert(range(10 * i, 10 * i + 5)); - return set; + for (std::uint32_t i = 1; i < 100; ++i) + { + boost::optional expected; + // no prev missing in domain for i <= 6 + if (i > 6) + { + std::uint32_t const oneBelowRange = (10 * (i / 10)) - 1; + + expected = ((i % 10) > 6) ? (i - 1) : oneBelowRange; + } + BEAST_EXPECT(prevMissing(set, i) == expected); + } } - void testMembership () + void + testToString() { - testcase ("membership"); + testcase("toString"); - RangeSet r1, r2; + RangeSet set; + BEAST_EXPECT(to_string(set) == "empty"); - r1.setRange (1, 10); - r1.clearValue (5); - r1.setRange (11, 20); + set.insert(1); + BEAST_EXPECT(to_string(set) == "1"); - r2.setRange (1, 4); - r2.setRange (6, 10); - r2.setRange (10, 20); + set.insert(range(4u, 6u)); + BEAST_EXPECT(to_string(set) == "1,4-6"); - BEAST_EXPECT(!r1.hasValue (5)); + set.insert(2); + BEAST_EXPECT(to_string(set) == "1-2,4-6"); - BEAST_EXPECT(r2.hasValue (9)); + set.erase(range(4u, 5u)); + BEAST_EXPECT(to_string(set) == "1-2,6"); } - - void testPrevMissing () + void + run() { - testcase ("prevMissing"); - - RangeSet const set = createPredefinedSet (); - - for (int i = 0; i < 100; ++i) - { - int const oneBelowRange = (10*(i/10))-1; - - int const expectedPrevMissing = - ((i % 10) > 6) ? (i-1) : oneBelowRange; - - BEAST_EXPECT(set.prevMissing (i) == expectedPrevMissing); - } - } - - void run () - { - testMembership (); - - testPrevMissing (); - - // TODO: Traverse functions must be tested + testPrevMissing(); + testToString(); } }; -BEAST_DEFINE_TESTSUITE(RangeSet,ripple_basics,ripple); - -} // ripple +BEAST_DEFINE_TESTSUITE(RangeSet, ripple_basics, ripple); +} // namespace ripple