From b449487a71c9e697a9f6ecd14a8e1c596fd01707 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Thu, 28 Jul 2016 20:45:51 +0100 Subject: [PATCH] refs #715 Support implicit conversion from CRange to QSet. --- src/blackmisc/iterator.h | 67 ++++++++++++++++++++++++++++++++++++++ src/blackmisc/range.h | 2 +- src/blackmisc/typetraits.h | 26 +++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/blackmisc/iterator.h b/src/blackmisc/iterator.h index ad03e3fd1..7ee8b2d6f 100644 --- a/src/blackmisc/iterator.h +++ b/src/blackmisc/iterator.h @@ -15,6 +15,7 @@ #define BLACKMISC_ITERATOR_H #include "optional.h" +#include "typetraits.h" #include #include #include @@ -26,6 +27,72 @@ namespace BlackMisc { namespace Iterators { + /*! + * Configurable output iterator using a provided functor to do the insertion. + */ + template class OutputIterator : public std::iterator + { + public: + //! Constructor + //! @{ + explicit OutputIterator(const F &func) : m_func(func) {} + explicit OutputIterator(F &&func) : m_func(std::move(func)) {} + //! @} + + //! Advance the iterator (no-op) + //! @{ + OutputIterator &operator ++() { return *this; } + OutputIterator operator ++(int) { return *this; } + //! @} + + //! Dereference (no-op) + OutputIterator &operator *() { return *this; } + + //! Assignment operator performs the output + template ::value, int> = 0> + OutputIterator &operator =(T &&value) { m_func(std::forward(value)); return *this; } + + //! Copy assignment operator + OutputIterator &operator =(const OutputIterator &other) + { + // Work around lambda's deleted copy assignment operator + this->~OutputIterator(); + return *new (this) OutputIterator(other); + } + + private: + F m_func; + }; + + /*! + * Return an output iterator of type deduced from the argument. + */ + template auto makeOutputIterator(F &&func) + { + return OutputIterator>(std::forward(func)); + } + + namespace Private + { + //! \private + template auto makeInsertIterator(T &container, std::true_type) + { + return makeOutputIterator([&container](auto &&v) { container.push_back(std::forward(v)); }); + } + //! \private + template auto makeInsertIterator(T &container, std::false_type) + { + return makeOutputIterator([&container](auto &&v) { container.insert(std::forward(v)); }); + } + } + + /*! + * Return an insert iterator appropriate to the container type (uses push_back or insert). + */ + template auto makeInsertIterator(T &container) + { + return Private::makeInsertIterator(container, HasPushBack()); + } /*! * Iterator wrapper for Qt's STL-style associative container iterators, when dereferenced return the key instead of the value. diff --git a/src/blackmisc/range.h b/src/blackmisc/range.h index d422d33d5..589258d1e 100644 --- a/src/blackmisc/range.h +++ b/src/blackmisc/range.h @@ -206,7 +206,7 @@ namespace BlackMisc T to() const { T container; - std::copy(begin(), end(), std::back_inserter(container)); + std::copy(begin(), end(), Iterators::makeInsertIterator(container)); return container; } diff --git a/src/blackmisc/typetraits.h b/src/blackmisc/typetraits.h index 210e2e2b5..de670c903 100644 --- a/src/blackmisc/typetraits.h +++ b/src/blackmisc/typetraits.h @@ -49,6 +49,32 @@ namespace BlackMisc //! \endcond #ifdef Q_CC_MSVC // work around what seems to be an expression SFINAE bug in MSVC + namespace Private + { + struct HasPushBackHelper + { + struct Base { int push_back; }; + template struct Derived : public T, public Base {}; + template struct TypeCheck {}; + template static std::false_type test(TypeCheck::push_back> *); + template static std::true_type test(...); + }; + } + template + using HasPushBack = decltype(Private::HasPushBackHelper::test(nullptr)); +#else + /*! + * Trait which is true if the expression a.push_back(v) is valid when a and v are instances of T and T::value_type. + */ + template > + struct HasPushBack : public std::false_type {}; + //! \cond + template + struct HasPushBack().push_back(std::declval()))>> : public std::true_type {}; + //! \endcond +#endif + +#ifdef Q_CC_MSVC namespace Private { struct HasGetLogCategoriesHelper