diff --git a/src/blackmisc/collection.h b/src/blackmisc/collection.h index 2fe56dc2e..7cf58deba 100644 --- a/src/blackmisc/collection.h +++ b/src/blackmisc/collection.h @@ -110,12 +110,12 @@ namespace BlackMisc iterator end() { return pimpl() ? pimpl()->end() : iterator(); } /*! - * \brief Returns iterator one past the end of the collection. + * \brief Returns const iterator one past the end of the collection. */ const_iterator end() const { return pimpl() ? pimpl()->end() : const_iterator(); } /*! - * \brief Returns iterator one past the end of the collection. + * \brief Returns const iterator one past the end of the collection. */ const_iterator cend() const { return pimpl() ? pimpl()->cend() : const_iterator(); } @@ -172,6 +172,27 @@ namespace BlackMisc */ iterator erase(iterator it1, iterator it2) { Q_ASSERT(pimpl()); return pimpl()->erase(it1, it2); } + /*! + * \brief Efficient find method using the find of the implementation container. Typically O(log n). + * \return An iterator to the position of the found element, or the end iterator if not found. + * \pre The sequence must be initialized. + * \warning Take care that the returned non-const iterator is not compared with a const iterator. + */ + iterator find(const T &value) { Q_ASSERT(pimpl()); return pimpl()->find(value); } + + /*! + * \brief Efficient find method using the find of the implementation container. Typically O(log n). + * \return An iterator to the position of the found element, or the end iterator if not found. + * \pre The sequence must be initialized. + */ + const_iterator find(const T &value) const { Q_ASSERT(pimpl()); return pimpl()->find(value); } + + /*! + * \brief Efficient remove using the find and erase of the implementation container. Typically O(log n). + * \pre The sequence must be initialized. + */ + void remove(const T &object) { auto it = find(object); if (it != end()) { erase(it); } } + /*! * \brief Test for equality. * \todo Improve inefficient implementation. @@ -203,16 +224,9 @@ namespace BlackMisc virtual iterator insert(const T &value) = 0; virtual iterator erase(iterator pos) = 0; virtual iterator erase(iterator it1, iterator it2) = 0; + virtual iterator find(const T &value) = 0; + virtual const_iterator find(const T &value) const = 0; virtual bool operator ==(const PimplBase &other) const = 0; - protected: - // using SFINAE to choose whether to implement insert() in terms of either push_back() or insert(), depending on which is available - // https://groups.google.com/forum/#!original/comp.lang.c++.moderated/T3x6lvmvvkQ/mfY5VTDJ--UJ - class yes { char x; }; class no { yes x[2]; }; template struct typecheck {}; - struct base { void push_back(); }; template struct derived : public C, public base {}; - static yes hasPushHelper(...); template static no hasPushHelper(D *, typecheck * = 0); - template struct hasPush : public std::integral_constant*)0)) == sizeof(yes)> {}; - template static iterator insertImpl(typename std::enable_if< hasPush::value, C>::type &c, const T &value) { c.push_back(value); return iterator::fromImpl(c.end() - 1); } - template static iterator insertImpl(typename std::enable_if < !hasPush::value, C >::type &c, const T &value) { return iterator::fromImpl(c.insert(value)); } }; template class Pimpl : public PimplBase @@ -231,13 +245,18 @@ namespace BlackMisc size_type size() const { return m_impl.size(); } bool empty() const { return m_impl.empty(); } void clear() { m_impl.clear(); } - iterator insert(const T &value) { return PimplBase::insertImpl(m_impl, value); } + iterator insert(const T &value) { return iterator::fromImpl(insertHelper(m_impl.insert(value))); } iterator erase(iterator pos) { return iterator::fromImpl(m_impl.erase(*static_cast(pos.getImpl()))); } //iterator erase(iterator it1, iterator it2) { return iterator::fromImpl(m_impl.erase(*static_cast(it1.getImpl()), *static_cast(it2.getImpl()))); } iterator erase(iterator it1, iterator it2) { while (it1 != it2) { it1 = iterator::fromImpl(m_impl.erase(*static_cast(it1.getImpl()))); } return it1; } + iterator find(const T &value) { return iterator::fromImpl(m_impl.find(value)); } + const_iterator find(const T &value) const { return const_iterator::fromImpl(m_impl.find(value)); } bool operator ==(const PimplBase &other) const { 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 + template static I insertHelper(I i) { return i; } + template static I insertHelper(std::pair p) { return p.first; } }; typedef QScopedPointer PimplPtr; diff --git a/src/blackmisc/containerbase.h b/src/blackmisc/containerbase.h index ed9b7b1b8..c35d01db9 100644 --- a/src/blackmisc/containerbase.h +++ b/src/blackmisc/containerbase.h @@ -27,6 +27,18 @@ namespace BlackMisc class CContainerBase : public CValueObject { public: + /*! + * \brief Return a new container of a different type, containing the same elements as this one. + * \tparam Other the type of the new container. + * \param other an optional initial value for the new container; will be copied. + */ + template