diff --git a/gtsam/base/FastSet.h b/gtsam/base/FastSet.h index 038921f91..0e54bbd19 100644 --- a/gtsam/base/FastSet.h +++ b/gtsam/base/FastSet.h @@ -18,11 +18,25 @@ #pragma once +#include + #include +#include +#include +#include #include +#include +#include + +BOOST_MPL_HAS_XXX_TRAIT_DEF(print) namespace gtsam { +// This is used internally to allow this container to be Testable even when it +// contains non-testable elements. +template +struct FastSetTestableHelper; + /** * FastSet is a thin wrapper around std::set that uses the boost * fast_pool_allocator instead of the default STL allocator. This is just a @@ -30,26 +44,94 @@ namespace gtsam { * we've seen that the fast_pool_allocator can lead to speedups of several %. * @ingroup base */ -template -class FastSet : public std::set, boost::fast_pool_allocator > { +template +class FastSet: public std::set, boost::fast_pool_allocator >, +public Testable > { public: typedef std::set, boost::fast_pool_allocator > Base; /** Default constructor */ - FastSet() {} + FastSet() { + } /** Constructor from a range, passes through to base class */ template - FastSet(INPUTITERATOR first, INPUTITERATOR last) : Base(first, last) {} + FastSet(INPUTITERATOR first, INPUTITERATOR last) : + Base(first, last) { + } /** Copy constructor from another FastSet */ - FastSet(const FastSet& x) : Base(x) {} + FastSet(const FastSet& x) : + Base(x) { + } /** Copy constructor from the base map class */ - FastSet(const Base& x) : Base(x) {} + FastSet(const Base& x) : + Base(x) { + } + /** Print to implement Testable */ + void print(const std::string& str = "") const { FastSetTestableHelper::print(*this, str); } + + /** Check for equality within tolerance to implement Testable */ + bool equals(const FastSet& other, double tol = 1e-9) const { return FastSetTestableHelper::equals(*this, other, tol); } +}; + +// This is the default Testable interface for *non*Testable elements, which +// uses stream operators. +template +struct FastSetTestableHelper { + + typedef FastSet Set; + + static void print(const Set& set, const std::string& str) { + std::cout << str << "\n"; + for (typename Set::const_iterator it = set.begin(); it != set.end(); ++it) + std::cout << " " << *it << "\n"; + std::cout.flush(); + } + + static bool equals(const Set& set1, const Set& set2, double tol) { + typename Set::const_iterator it1 = set1.begin(); + typename Set::const_iterator it2 = set2.begin(); + while (it1 != set1.end()) { + if (it2 == set2.end() || + fabs((double)(*it1) - (double)(*it2) > tol)) + return false; + ++it1; + ++it2; + } + return true; + } +}; + +// This is the Testable interface for Testable elements +template +struct FastSetTestableHelper >::type> { + + typedef FastSet Set; + + static void print(const Set& set, const std::string& str) { + std::cout << str << "\n"; + for (typename Set::const_iterator it = set.begin(); it != set.end(); ++it) + it->print(" "); + std::cout.flush(); + } + + static bool equals(const Set& set1, const Set& set2, double tol) { + typename Set::const_iterator it1 = set1.begin(); + typename Set::const_iterator it2 = set2.begin(); + while (it1 != set1.end()) { + if (it2 == set2.end() || + !it1->equals(*it2, tol)) + return false; + ++it1; + ++it2; + } + return true; + } }; }