mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-08 03:35:35 +08:00
generic type-erased container types CSequence and CCollection, including predicate-based algorithms
refs #81
This commit is contained in:
653
src/blackmisc/iterator.h
Normal file
653
src/blackmisc/iterator.h
Normal file
@@ -0,0 +1,653 @@
|
||||
/* Copyright (C) 2013 VATSIM Community / authors
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*!
|
||||
\file
|
||||
*/
|
||||
|
||||
#ifndef BLACKMISC_ITERATOR_H
|
||||
#define BLACKMISC_ITERATOR_H
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Iterators
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief Generic type-erased const forward iterator with value semantics.
|
||||
* \tparam T the value_type of the container being iterated over.
|
||||
*
|
||||
* Can take any suitable iterator type as its implementation at runtime.
|
||||
*/
|
||||
template <class T> class ConstForwardIterator
|
||||
{
|
||||
public:
|
||||
//! \brief STL compatibility
|
||||
//! @{
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef const T *pointer;
|
||||
typedef const T &reference;
|
||||
typedef const T *const_pointer;
|
||||
typedef const T &const_reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
//! @}
|
||||
|
||||
//! \brief Default constructor.
|
||||
ConstForwardIterator() {}
|
||||
|
||||
/*!
|
||||
* \brief Constructor.
|
||||
* \param i
|
||||
*/
|
||||
template <class I> ConstForwardIterator(I i) : m_pimpl(new Pimpl<I>(std::move(i))) {}
|
||||
|
||||
/*!
|
||||
* \brief Copy constructor.
|
||||
* \param other
|
||||
*/
|
||||
ConstForwardIterator(const ConstForwardIterator &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {}
|
||||
|
||||
/*!
|
||||
* \brief Move constructor.
|
||||
* \param other
|
||||
*/
|
||||
ConstForwardIterator(ConstForwardIterator &&other) : m_pimpl(other.m_pimpl.take()) {}
|
||||
|
||||
/*!
|
||||
* \brief Assignment.
|
||||
* \param i
|
||||
* \return
|
||||
*/
|
||||
template <class I> ConstForwardIterator &operator =(I i) { m_pimpl.reset(new Pimpl<I>(std::move(i))); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Copy assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
ConstForwardIterator &operator =(const ConstForwardIterator &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Move assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
ConstForwardIterator &operator =(ConstForwardIterator &&other) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_reference operator *() const { Q_ASSERT(m_pimpl); return **pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Arrow operator provides access to members of the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_pointer operator ->() const { Q_ASSERT(m_pimpl); return &**pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Prefix increment operator advances the iterator.
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstForwardIterator &operator ++() { Q_ASSERT(m_pimpl); ++*pimpl(); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Postfix increment operator advances the iterator.
|
||||
* \return Copy of the iterator in the old position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstForwardIterator operator ++(int) { Q_ASSERT(m_pimpl); auto copy = *this; ++*pimpl(); return copy; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstForwardIterator operator +=(difference_type n) { Q_ASSERT(m_pimpl); *pimpl() += n; return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Copy of the iterator in its new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstForwardIterator operator +(difference_type n) const { auto copy = *this; return copy += n; }
|
||||
|
||||
/*!
|
||||
* \brief Test for equality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator ==(const ConstForwardIterator &other) const { return (pimpl() && other.pimpl()) ? *pimpl() == *other.pimpl() : pimpl() == other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Test for inequality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator !=(const ConstForwardIterator &other) const { return !(*this == other); }
|
||||
|
||||
/*!
|
||||
* \brief Return opaque pointer to underlying implementation iterator object.
|
||||
* \return
|
||||
* \pre The iterator must have been initialized.
|
||||
* \todo Returning by void* is rotten, but GCC gives a very cryptic error if I make it a function template with a cast inside.
|
||||
*/
|
||||
void *getImpl() { return pimpl()->impl(); }
|
||||
|
||||
private:
|
||||
class PimplBase
|
||||
{
|
||||
public:
|
||||
virtual ~PimplBase() {}
|
||||
virtual PimplBase *clone() const = 0;
|
||||
virtual const_reference operator *() const = 0;
|
||||
virtual void operator ++() = 0;
|
||||
virtual void operator +=(difference_type) = 0;
|
||||
virtual bool operator ==(const PimplBase &) const = 0;
|
||||
virtual void *impl() = 0;
|
||||
};
|
||||
|
||||
template <class I> class Pimpl : public PimplBase
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_same<T, typename std::iterator_traits<I>::value_type>::value,
|
||||
"ConstForwardIterator must be initialized from an iterator with the same value_type.");
|
||||
Pimpl(I &&i) : m_impl(std::move(i)) {}
|
||||
virtual PimplBase *clone() const { return new Pimpl(*this); }
|
||||
virtual const_reference operator *() const { return *m_impl; }
|
||||
virtual void operator ++() { ++m_impl; }
|
||||
virtual void operator +=(difference_type n) { m_impl += n; }
|
||||
virtual bool operator ==(const PimplBase &other) const { return m_impl == static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual void *impl() { return &m_impl; }
|
||||
private:
|
||||
I m_impl;
|
||||
};
|
||||
|
||||
typedef QScopedPointer<PimplBase> PimplPtr;
|
||||
PimplPtr m_pimpl;
|
||||
|
||||
// using these methods to access m_pimpl.data() eases the cognitive burden of correctly forwarding const
|
||||
PimplBase *pimpl() { return m_pimpl.data(); }
|
||||
const PimplBase *pimpl() const { return m_pimpl.data(); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Generic type-erased const bidirectional iterator with value semantics.
|
||||
* \tparam T the value_type of the container being iterated over.
|
||||
*
|
||||
* Can take any suitable iterator type as its implementation at runtime.
|
||||
*/
|
||||
template <class T> class ConstBidirectionalIterator
|
||||
{
|
||||
public:
|
||||
//! \brief STL compatibility
|
||||
//! @{
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef const T *pointer;
|
||||
typedef const T &reference;
|
||||
typedef const T *const_pointer;
|
||||
typedef const T &const_reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
//! @}
|
||||
|
||||
//! \brief Default constructor.
|
||||
ConstBidirectionalIterator() {}
|
||||
|
||||
/*!
|
||||
* \brief Constructor.
|
||||
* \param i
|
||||
*/
|
||||
template <class I> ConstBidirectionalIterator(I i) : m_pimpl(new Pimpl<I>(std::move(i))) {}
|
||||
|
||||
/*!
|
||||
* \brief Copy constructor.
|
||||
* \param other
|
||||
*/
|
||||
ConstBidirectionalIterator(const ConstBidirectionalIterator &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {}
|
||||
|
||||
/*!
|
||||
* \brief Move constructor.
|
||||
* \param other
|
||||
*/
|
||||
ConstBidirectionalIterator(ConstBidirectionalIterator &&other) : m_pimpl(other.m_pimpl.take()) {}
|
||||
|
||||
/*!
|
||||
* \brief Assignment.
|
||||
* \param i
|
||||
* \return
|
||||
*/
|
||||
template <class I> ConstBidirectionalIterator &operator =(I i) { m_pimpl.reset(new Pimpl<I>(std::move(i))); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Copy assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
ConstBidirectionalIterator &operator =(const ConstBidirectionalIterator &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Move assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
ConstBidirectionalIterator &operator =(ConstBidirectionalIterator &&other) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_reference operator *() const { Q_ASSERT(m_pimpl); return **pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Arrow operator provides access to members of the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_pointer operator ->() const { Q_ASSERT(m_pimpl); return &**pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Prefix increment operator advances the iterator.
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator &operator ++() { Q_ASSERT(m_pimpl); ++*pimpl(); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Postfix increment operator advances the iterator.
|
||||
* \return Copy of the iterator in the old position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator ++(int) { Q_ASSERT(m_pimpl); auto copy = *this; ++*pimpl(); return copy; }
|
||||
|
||||
/*!
|
||||
* \brief Prefix decrement operator backtracks the iterator.
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator &operator --() { Q_ASSERT(m_pimpl); --*pimpl(); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Postfix decrement operator backtracks the iterator.
|
||||
* \return Copy of the iterator at the old position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator --(int) { Q_ASSERT(m_pimpl); auto copy = *this; --*pimpl(); return copy; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator +=(difference_type n) { Q_ASSERT(m_pimpl); *pimpl() += n; return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Copy of the iterator in its new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator +(difference_type n) const { auto copy = *this; return copy += n; }
|
||||
|
||||
/*!
|
||||
* \brief Backtrack the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator -=(difference_type n) { Q_ASSERT(m_pimpl); *pimpl() -= n; return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Backtrack the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Copy of the iterator in its new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
ConstBidirectionalIterator operator -(difference_type n) const { auto copy = *this; return copy -= n; }
|
||||
|
||||
/*!
|
||||
* \brief Return the distance between two iterators.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
difference_type operator -(const ConstBidirectionalIterator &other) const { Q_ASSERT(m_pimpl && other.m_pimpl); return *pimpl() - *other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Test for equality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator ==(const ConstBidirectionalIterator &other) const { return (pimpl() && other.pimpl()) ? *pimpl() == *other.pimpl() : pimpl() == other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Test for inequality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator !=(const ConstBidirectionalIterator &other) const { return !(*this == other); }
|
||||
|
||||
/*!
|
||||
* \brief For sorting.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator <(const ConstBidirectionalIterator &other) const { Q_ASSERT(m_pimpl && other.m_pimpl); return *pimpl() < *other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Return opaque pointer to underlying implementation iterator object.
|
||||
* \return
|
||||
* \pre The iterator must have been initialized.
|
||||
* \todo Returning by void* is rotten, but GCC gives a very cryptic error if I make it a function template with a cast inside.
|
||||
*/
|
||||
void *getImpl() { return pimpl()->impl(); }
|
||||
|
||||
private:
|
||||
class PimplBase
|
||||
{
|
||||
public:
|
||||
virtual ~PimplBase() {}
|
||||
virtual PimplBase *clone() const = 0;
|
||||
virtual const_reference operator *() const = 0;
|
||||
virtual void operator ++() = 0;
|
||||
virtual void operator --() = 0;
|
||||
virtual void operator +=(difference_type) = 0;
|
||||
virtual void operator -=(difference_type) = 0;
|
||||
virtual difference_type operator -(const PimplBase &) const = 0;
|
||||
virtual bool operator ==(const PimplBase &) const = 0;
|
||||
virtual bool operator <(const PimplBase &) const = 0;
|
||||
virtual void *impl() = 0;
|
||||
};
|
||||
|
||||
template <class I> class Pimpl : public PimplBase
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_same<T, typename std::iterator_traits<I>::value_type>::value,
|
||||
"ConstBidirectionalIterator must be initialized from an iterator with the same value_type.");
|
||||
Pimpl(I &&i) : m_impl(std::move(i)) {}
|
||||
virtual PimplBase *clone() const { return new Pimpl(*this); }
|
||||
virtual const_reference operator *() const { return *m_impl; }
|
||||
virtual void operator ++() { ++m_impl; }
|
||||
virtual void operator --() { --m_impl; }
|
||||
virtual void operator +=(difference_type n) { m_impl += n; }
|
||||
virtual void operator -=(difference_type n) { m_impl -= n; }
|
||||
virtual difference_type operator -(const PimplBase &other) const { return m_impl - static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual bool operator ==(const PimplBase &other) const { return m_impl == static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual bool operator <(const PimplBase &other) const { return m_impl < static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual void *impl() { return &m_impl; }
|
||||
private:
|
||||
I m_impl;
|
||||
};
|
||||
|
||||
typedef QScopedPointer<PimplBase> PimplPtr;
|
||||
PimplPtr m_pimpl;
|
||||
|
||||
// using these methods to access m_pimpl.data() eases the cognitive burden of correctly forwarding const
|
||||
PimplBase *pimpl() { return m_pimpl.data(); }
|
||||
const PimplBase *pimpl() const { return m_pimpl.data(); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Generic type-erased non-const bidirectional iterator with value semantics.
|
||||
* \tparam T the value_type of the container being iterated over.
|
||||
*
|
||||
* Can take any suitable iterator type as its implementation at runtime.
|
||||
*/
|
||||
template <class T> class BidirectionalIterator
|
||||
{
|
||||
public:
|
||||
//! \brief STL compatibility
|
||||
//! @{
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T *pointer;
|
||||
typedef T &reference;
|
||||
typedef const T *const_pointer;
|
||||
typedef const T &const_reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
//! @}
|
||||
|
||||
//! \brief Default constructor.
|
||||
BidirectionalIterator() {}
|
||||
|
||||
/*!
|
||||
* \brief Constructor.
|
||||
* \param i
|
||||
*/
|
||||
template <class I> BidirectionalIterator(I i) : m_pimpl(new Pimpl<I>(std::move(i))) {}
|
||||
|
||||
/*!
|
||||
* \brief Copy constructor.
|
||||
* \param other
|
||||
*/
|
||||
BidirectionalIterator(const BidirectionalIterator &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {}
|
||||
|
||||
/*!
|
||||
* \brief Move constructor.
|
||||
* \param other
|
||||
*/
|
||||
BidirectionalIterator(BidirectionalIterator &&other) : m_pimpl(other.m_pimpl.take()) {}
|
||||
|
||||
/*!
|
||||
* \brief Assignment.
|
||||
* \param i
|
||||
* \return
|
||||
*/
|
||||
template <class I> BidirectionalIterator &operator =(I i) { m_pimpl.reset(new Pimpl<I>(std::move(i))); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Copy assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
BidirectionalIterator &operator =(const BidirectionalIterator &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Move assignment.
|
||||
* \param other
|
||||
* \return
|
||||
*/
|
||||
BidirectionalIterator &operator =(BidirectionalIterator &&other) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_reference operator *() const { Q_ASSERT(m_pimpl); return **pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
reference operator *() { Q_ASSERT(m_pimpl); return **pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Arrow operator provides access to members of the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
const_pointer operator ->() const { Q_ASSERT(m_pimpl); return &**pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Arrow operator provides access to members of the object pointed to.
|
||||
* \return
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
pointer operator ->() { Q_ASSERT(m_pimpl); return &**pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Prefix increment operator advances the iterator.
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator &operator ++() { Q_ASSERT(m_pimpl); ++*pimpl(); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Postfix increment operator advances the iterator.
|
||||
* \return Copy of the iterator in the old position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator ++(int) { Q_ASSERT(m_pimpl); auto copy = *this; ++*pimpl(); return copy; }
|
||||
|
||||
/*!
|
||||
* \brief Prefix decrement operator backtracks the iterator.
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator &operator --() { Q_ASSERT(m_pimpl); --*pimpl(); return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Postfix decrement operator backtracks the iterator.
|
||||
* \return Copy of the iterator at the old position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator --(int) { Q_ASSERT(m_pimpl); auto copy = *this; --*pimpl(); return copy; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator +=(difference_type n) { Q_ASSERT(m_pimpl); *pimpl() += n; return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Advance the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Copy of the iterator in its new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator +(difference_type n) const { auto copy = *this; return copy += n; }
|
||||
|
||||
/*!
|
||||
* \brief Backtrack the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Reference to the iterator at the new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator -=(difference_type n) { Q_ASSERT(m_pimpl); *pimpl() -= n; return *this; }
|
||||
|
||||
/*!
|
||||
* \brief Backtrack the iterator by a certain amount.
|
||||
* \param n
|
||||
* \return Copy of the iterator in its new position.
|
||||
* \pre The iterator must be initialized and valid.
|
||||
*/
|
||||
BidirectionalIterator operator -(difference_type n) const { auto copy = *this; return copy -= n; }
|
||||
|
||||
/*!
|
||||
* \brief Return the distance between two iterators.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
difference_type operator -(const BidirectionalIterator &other) const { Q_ASSERT(m_pimpl && other.m_pimpl); return *pimpl() - *other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Test for equality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator ==(const BidirectionalIterator &other) const { return (pimpl() && other.pimpl()) ? *pimpl() == *other.pimpl() : pimpl() == other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Test for inequality.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator !=(const BidirectionalIterator &other) const { return !(*this == other); }
|
||||
|
||||
/*!
|
||||
* \brief For sorting.
|
||||
* \param other
|
||||
* \return
|
||||
* \pre Both iterators must originate from the same collection, and not mix begin/end with cbegin/cend.
|
||||
*/
|
||||
bool operator <(const BidirectionalIterator &other) const { Q_ASSERT(m_pimpl && other.m_pimpl); return *pimpl() < *other.pimpl(); }
|
||||
|
||||
/*!
|
||||
* \brief Return opaque pointer to underlying implementation iterator object.
|
||||
* \return
|
||||
* \pre The iterator must have been initialized.
|
||||
* \todo Returning by void* is rotten, but GCC gives a very cryptic error if I make it a function template with a cast inside.
|
||||
*/
|
||||
void *getImpl() { return pimpl()->impl(); }
|
||||
|
||||
private:
|
||||
class PimplBase
|
||||
{
|
||||
public:
|
||||
virtual ~PimplBase() {}
|
||||
virtual PimplBase *clone() const = 0;
|
||||
virtual const_reference operator *() const = 0;
|
||||
virtual reference operator *() = 0;
|
||||
virtual void operator ++() = 0;
|
||||
virtual void operator --() = 0;
|
||||
virtual void operator +=(difference_type) = 0;
|
||||
virtual void operator -=(difference_type) = 0;
|
||||
virtual difference_type operator -(const PimplBase &) const = 0;
|
||||
virtual bool operator ==(const PimplBase &) const = 0;
|
||||
virtual bool operator <(const PimplBase &) const = 0;
|
||||
virtual void *impl() = 0;
|
||||
};
|
||||
|
||||
template <class I> class Pimpl : public PimplBase
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_same<T, typename std::iterator_traits<I>::value_type>::value,
|
||||
"BidirectionalIterator must be initialized from an iterator with the same value_type.");
|
||||
Pimpl(I &&i) : m_impl(std::move(i)) {}
|
||||
virtual PimplBase *clone() const { return new Pimpl(*this); }
|
||||
virtual const_reference operator *() const { return *m_impl; }
|
||||
virtual reference operator *() { return *m_impl; }
|
||||
virtual void operator ++() { ++m_impl; }
|
||||
virtual void operator --() { --m_impl; }
|
||||
virtual void operator +=(difference_type n) { m_impl += n; }
|
||||
virtual void operator -=(difference_type n) { m_impl -= n; }
|
||||
virtual difference_type operator -(const PimplBase &other) const { return m_impl - static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual bool operator ==(const PimplBase &other) const { return m_impl == static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual bool operator <(const PimplBase &other) const { return m_impl < static_cast<const Pimpl&>(other).m_impl; }
|
||||
virtual void *impl() { return &m_impl; }
|
||||
private:
|
||||
I m_impl;
|
||||
};
|
||||
|
||||
typedef QScopedPointer<PimplBase> PimplPtr;
|
||||
PimplPtr m_pimpl;
|
||||
|
||||
// using these methods to access m_pimpl.data() eases the cognitive burden of correctly forwarding const
|
||||
PimplBase *pimpl() { return m_pimpl.data(); }
|
||||
const PimplBase *pimpl() const { return m_pimpl.data(); }
|
||||
};
|
||||
|
||||
} //namespace Iterators
|
||||
|
||||
} //namespace BlackMisc
|
||||
|
||||
#endif //BLACKMISC_ITERATOR_H
|
||||
Reference in New Issue
Block a user