diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index a1891164f64..8d7da9fb00b 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -111,6 +111,12 @@ class STPathElement final : public CountedObject bool operator!=(STPathElement const& t) const; + [[nodiscard]] std::size_t + hash() const noexcept + { + return hash_value_; + } + private: static std::size_t getHash(STPathElement const& element); diff --git a/src/xrpld/rpc/detail/Pathfinder.cpp b/src/xrpld/rpc/detail/Pathfinder.cpp index 9a34cf44f1c..42b3c412adf 100644 --- a/src/xrpld/rpc/detail/Pathfinder.cpp +++ b/src/xrpld/rpc/detail/Pathfinder.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include namespace xrpl { @@ -978,16 +979,10 @@ Pathfinder::isNoRippleOut(STPath const& currentPath) } void -addUniquePath(STPathSet& pathSet, STPath const& path) +addUniquePath(STPathSet& pathSet, std::unordered_set& index, STPath const& path) { - // TODO(tom): building an STPathSet this way is quadratic in the size - // of the STPathSet! - for (auto const& p : pathSet) - { - if (p == path) - return; - } - pathSet.pushBack(path); + if (index.insert(path).second) + pathSet.pushBack(path); } void @@ -1021,7 +1016,7 @@ Pathfinder::addLink( { // non-default path to XRP destination JLOG(j_.trace()) << "complete path found ax: " << currentPath.getJson(JsonOptions::KNone); - addUniquePath(completePaths_, currentPath); + addUniquePath(completePaths_, completePathsIndex_, currentPath); } } else @@ -1124,7 +1119,8 @@ Pathfinder::addLink( { JLOG(j_.trace()) << "complete path found ae: " << currentPath.getJson(JsonOptions::KNone); - addUniquePath(completePaths_, currentPath); + addUniquePath( + completePaths_, completePathsIndex_, currentPath); } } else if (!bDestOnly) @@ -1255,7 +1251,7 @@ Pathfinder::addLink( // complete JLOG(j_.trace()) << "complete path found bx: " << currentPath.getJson(JsonOptions::KNone); - addUniquePath(completePaths_, newPath); + addUniquePath(completePaths_, completePathsIndex_, newPath); } else { @@ -1301,7 +1297,7 @@ Pathfinder::addLink( // complete JLOG(j_.trace()) << "complete path found ba: " << currentPath.getJson(JsonOptions::KNone); - addUniquePath(completePaths_, newPath); + addUniquePath(completePaths_, completePathsIndex_, newPath); } else { diff --git a/src/xrpld/rpc/detail/Pathfinder.h b/src/xrpld/rpc/detail/Pathfinder.h index ba1fc453b39..fc375908d91 100644 --- a/src/xrpld/rpc/detail/Pathfinder.h +++ b/src/xrpld/rpc/detail/Pathfinder.h @@ -10,8 +10,22 @@ #include #include +#include + namespace xrpl { +struct STPathHash +{ + std::size_t + operator()(STPath const& path) const noexcept + { + std::size_t h = path.size(); + for (auto const& elem : path) + h ^= elem.hash() + 0x9e3779b9 + (h << 6) + (h >> 2); + return h; + } +}; + /** Calculates payment paths. The @ref RippleCalc determines the quality of the found paths. @@ -187,6 +201,7 @@ class Pathfinder : public CountedObject STPathElement source_; STPathSet completePaths_; + std::unordered_set completePathsIndex_; std::vector pathRanks_; std::map paths_;