diff --git a/src/blackmisc/collection.h b/src/blackmisc/collection.h index b32b04967..7a7393e8d 100644 --- a/src/blackmisc/collection.h +++ b/src/blackmisc/collection.h @@ -22,7 +22,21 @@ namespace BlackMisc { /*! - * \brief Generic type-erased unsequenced container with value semantics. + * Needed for compatibility with C++ standard algorithms which expect ordered sets. + */ + template + class QOrderedSet : public QMap + { + public: + //! Type of values stored in the set. + typedef T value_type; + + //! Insert a new value into the set. + typename QMap::iterator insert(const T &value) { return QMap::insert(value, value); } + }; + + /*! + * \brief Generic type-erased ordered container with value semantics. * \tparam T the type of elements contained. * * Can take any suitable container class as its implementation at runtime. @@ -48,7 +62,7 @@ namespace BlackMisc /*! * \brief Default constructor. */ - CCollection() : m_pimpl(new Pimpl>(QSet())) {} + CCollection() : m_pimpl(new Pimpl>(QOrderedSet())) {} /*! * \brief Copy constructor. @@ -286,7 +300,7 @@ namespace BlackMisc bool operator ==(const PimplBase &other) const override { Pimpl copy = C(); for (auto i = other.cbegin(); i != other.cend(); ++i) copy.insert(*i); return m_impl == copy.m_impl; } private: C m_impl; - // insertHelper: QSet::insert returns an iterator, but std::set::insert returns a std::pair + // insertHelper: QOrderedSet::insert returns an iterator, but std::set::insert returns a std::pair template static I insertHelper(I i) { return i; } template static I insertHelper(std::pair p) { return p.first; } }; @@ -307,6 +321,6 @@ Q_DECLARE_METATYPE(BlackMisc::CCollection) Q_DECLARE_METATYPE(BlackMisc::CCollection) Q_DECLARE_METATYPE(BlackMisc::CCollection) Q_DECLARE_METATYPE(BlackMisc::CCollection) -// CCollection not instantiated because QSet is not supported due to hashing constraints +// CCollection not instantiated due to it being a dumb idea because of rounding issues #endif // guard diff --git a/src/blackmisc/valueobject.h b/src/blackmisc/valueobject.h index f5fe4c4b8..177f2b7c9 100644 --- a/src/blackmisc/valueobject.h +++ b/src/blackmisc/valueobject.h @@ -21,6 +21,25 @@ namespace BlackMisc // forward declaration class CIndexVariantMap; + namespace PhysicalQuantities + { + template class CPhysicalQuantity; // forward declaration + + //! Traits class to test whether a class is a physical quantity class. Useful for enable_if. + template + class IsQuantity + { + struct yes { char x; }; + struct no { yes x[2]; }; + template static yes test(const CPhysicalQuantity &); + static no test(...); + + public: + //! True if and only if T is derived from CPhysicalQuantity. + static const bool value = sizeof(test(*(T*)0)) == sizeof(yes); + }; + } + /*! * \brief Base class for value objects. * Public non-virtual interface with protected virtual implementation. @@ -81,6 +100,42 @@ namespace BlackMisc //! Operator != with value map friend bool operator!=(const CValueObject &valueObject, const CIndexVariantMap &valueMap); + //! Comparison operator to allow valueobjects be used as keys in QMap and std::set. + template friend typename std::enable_if::value && ! PhysicalQuantities::IsQuantity::value, bool>::type + operator<(const T &lhs, const T &rhs) + { + const auto &lhsBase = static_cast(lhs); + const auto &rhsBase = static_cast(rhs); + return lhsBase.compareImpl(rhsBase) < 0; + } + + //! Comparison for symmetry with operator<. + template friend typename std::enable_if::value && ! PhysicalQuantities::IsQuantity::value, bool>::type + operator>(const T &lhs, const T &rhs) + { + const auto &lhsBase = static_cast(lhs); + const auto &rhsBase = static_cast(rhs); + return lhsBase.compareImpl(rhsBase) > 0; + } + + //! Comparison for symmetry with operator<. + template friend typename std::enable_if::value && ! PhysicalQuantities::IsQuantity::value, bool>::type + operator<=(const T &lhs, const T &rhs) + { + const auto &lhsBase = static_cast(lhs); + const auto &rhsBase = static_cast(rhs); + return lhsBase.compareImpl(rhsBase) <= 0; + } + + //! Comparison for symmetry with operator<. + template friend typename std::enable_if::value && ! PhysicalQuantities::IsQuantity::value, bool>::type + operator>=(const T &lhs, const T &rhs) + { + const auto &lhsBase = static_cast(lhs); + const auto &rhsBase = static_cast(rhs); + return lhsBase.compareImpl(rhsBase) >= 0; + } + /*! * Compares two instances of related classes * and returns an integer less than, equal to, or greater than zero