From a6fad0508f35aa27c80beffb57fc3ab6a54bf551 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Thu, 3 Jul 2014 18:59:39 +0100 Subject: [PATCH] refs #290 added CRange, a conceptual container constructed from a begin and end iterator of a real container, which allows making a pseudo-copy of a container without copying the elements inside --- src/blackmisc/range.h | 122 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/blackmisc/range.h b/src/blackmisc/range.h index 540eeaf84..3a86c1635 100644 --- a/src/blackmisc/range.h +++ b/src/blackmisc/range.h @@ -91,6 +91,128 @@ namespace BlackMisc const Derived &derived() const { return static_cast(*this); } }; + /*! + * A range is a conceptual container which does not contain any elements of its own, + * but is constructed from a begin iterator and an end iterator of another container. + * + * By using iterator wrappers, it is possible to use CRange to iterate over the results of predicate methods without copying elements. + * + * \warning Remember that the iterators in the range refer to elements in the original container, + * so take care that the original container remains valid and does not invalidate its iterators + * during the lifetime of the range. + */ + template + class CRange : public CRangeBase, typename std::iterator_traits::value_type> + { + public: + //! STL compatibility + //! @{ + typedef typename std::iterator_traits::value_type key_type; + typedef typename std::iterator_traits::value_type value_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef value_type *pointer; + typedef const value_type *const_pointer; + typedef I const_iterator; + typedef I iterator; + typedef typename std::iterator_traits::difference_type difference_type; + //! @} + + //! Constructor. + CRange(I begin, I end) : m_begin(begin), m_end(end) {} + + //! Begin and end iterators. + //! @{ + const_iterator begin() const { return m_begin; } + const_iterator cbegin() const { return m_begin; } + const_iterator end() const { return m_end; } + const_iterator cend() const { return m_end; } + //! @} + + //! Implicit conversion to any container of value_type which supports push_back. This will copy elements. + template ::value>::type> + operator T() const + { + T container; + std::copy(begin(), end(), std::back_inserter(container)); + return container; + } + + //! Returns true if the range is empty. + //! @{ + bool empty() const { return begin() == end(); } + bool isEmpty() const { return empty(); } + //! @} + + //! Returns the element at the beginning of the range. Undefined if the range is empty. + const_reference front() const { return *begin(); } + + //! Returns the element at the beginning of the range, or a default value if the range is empty. + const_reference frontOrDefault() const + { + static const value_type def; + return empty() ? def : *begin(); + } + + //! Returns the element at the beginning of the range, or a default value if the range is empty. + value_type frontOrDefault(value_type def) const + { + return empty() ? def : *begin(); + } + + private: + I m_begin; + I m_end; + }; + + /*! + * Streaming operators for CRange to qDebug. + */ + //! @{ + template + QDebug operator <<(QDebug d, const CRange &range) + { + for (const auto &v : range) { d << v; } + return d; + } + template + QNoDebug operator <<(QNoDebug d, const CRange &) + { + return d; + } + //! @} + + /*! + * Returns a CRange constructed from begin and end iterators of deduced types. + * \param begin The begin iterator. + * \param end The end iterator, which can be any iterator type convertible to I. + */ + template + auto makeRange(I begin, I2 end) -> CRange + { + return { begin, static_cast(end) }; + } + + /*! + * Returns a CRange constructed from the begin and end iterators of the given container. + * + * The returned CRange may or may not be const, depending on the constness of the container. + */ + template + auto makeRange(T &&container) -> CRange + { + return { container.begin(), container.end() }; + } + + /*! + * Returns a const CRange constructed from the cbegin and cend iterators of the given container. + */ + template + auto makeConstRange(T &&container) -> CRange + { + return { container.cbegin(), container.cend() }; + } + } #endif // guard