preparatory to refs #230, need to replace QSet with QOrderedSet

(which is our own custom class) in order to support standard algorithms.
This also means adding generic comparison operators for CValueObject.
This commit is contained in:
Mathew Sutcliffe
2014-05-06 18:13:10 +01:00
parent e076248cd9
commit 18453225bd
2 changed files with 73 additions and 4 deletions

View File

@@ -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 T>
class QOrderedSet : public QMap<T, T>
{
public:
//! Type of values stored in the set.
typedef T value_type;
//! Insert a new value into the set.
typename QMap<T, T>::iterator insert(const T &value) { return QMap<T, T>::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<T>>(QSet<T>())) {}
CCollection() : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>())) {}
/*!
* \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<interator, bool>
// insertHelper: QOrderedSet::insert returns an iterator, but std::set::insert returns a std::pair<interator, bool>
template <class I> static I insertHelper(I i) { return i; }
template <class I> static I insertHelper(std::pair<I, bool> p) { return p.first; }
};
@@ -307,6 +321,6 @@ Q_DECLARE_METATYPE(BlackMisc::CCollection<int>)
Q_DECLARE_METATYPE(BlackMisc::CCollection<uint>)
Q_DECLARE_METATYPE(BlackMisc::CCollection<qlonglong>)
Q_DECLARE_METATYPE(BlackMisc::CCollection<qulonglong>)
// CCollection<double> not instantiated because QSet<double> is not supported due to hashing constraints
// CCollection<double> not instantiated due to it being a dumb idea because of rounding issues
#endif // guard

View File

@@ -21,6 +21,25 @@ namespace BlackMisc
// forward declaration
class CIndexVariantMap;
namespace PhysicalQuantities
{
template <class MU, class PQ> class CPhysicalQuantity; // forward declaration
//! Traits class to test whether a class is a physical quantity class. Useful for enable_if.
template <class T>
class IsQuantity
{
struct yes { char x; };
struct no { yes x[2]; };
template <class MU, class PQ> static yes test(const CPhysicalQuantity<MU, PQ> &);
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 <class T> friend typename std::enable_if<std::is_base_of<CValueObject, T>::value && ! PhysicalQuantities::IsQuantity<T>::value, bool>::type
operator<(const T &lhs, const T &rhs)
{
const auto &lhsBase = static_cast<const CValueObject &>(lhs);
const auto &rhsBase = static_cast<const CValueObject &>(rhs);
return lhsBase.compareImpl(rhsBase) < 0;
}
//! Comparison for symmetry with operator<.
template <class T> friend typename std::enable_if<std::is_base_of<CValueObject, T>::value && ! PhysicalQuantities::IsQuantity<T>::value, bool>::type
operator>(const T &lhs, const T &rhs)
{
const auto &lhsBase = static_cast<const CValueObject &>(lhs);
const auto &rhsBase = static_cast<const CValueObject &>(rhs);
return lhsBase.compareImpl(rhsBase) > 0;
}
//! Comparison for symmetry with operator<.
template <class T> friend typename std::enable_if<std::is_base_of<CValueObject, T>::value && ! PhysicalQuantities::IsQuantity<T>::value, bool>::type
operator<=(const T &lhs, const T &rhs)
{
const auto &lhsBase = static_cast<const CValueObject &>(lhs);
const auto &rhsBase = static_cast<const CValueObject &>(rhs);
return lhsBase.compareImpl(rhsBase) <= 0;
}
//! Comparison for symmetry with operator<.
template <class T> friend typename std::enable_if<std::is_base_of<CValueObject, T>::value && ! PhysicalQuantities::IsQuantity<T>::value, bool>::type
operator>=(const T &lhs, const T &rhs)
{
const auto &lhsBase = static_cast<const CValueObject &>(lhs);
const auto &rhsBase = static_cast<const CValueObject &>(rhs);
return lhsBase.compareImpl(rhsBase) >= 0;
}
/*!
* Compares two instances of related classes
* and returns an integer less than, equal to, or greater than zero