Doxygen style.

This commit is contained in:
Mathew Sutcliffe
2016-07-02 01:40:00 +01:00
parent 8d5020d78e
commit e20c8bbcbd
6 changed files with 292 additions and 572 deletions

View File

@@ -51,7 +51,7 @@ namespace BlackMisc
}; };
/*! /*!
* \brief Generic type-erased ordered container with value semantics. * Generic type-erased ordered container with value semantics.
* \tparam T the type of elements contained. * \tparam T the type of elements contained.
* *
* Can take any suitable container class as its implementation at runtime. * Can take any suitable container class as its implementation at runtime.
@@ -62,7 +62,7 @@ namespace BlackMisc
public Mixin::Icon<CCollection<T>> public Mixin::Icon<CCollection<T>>
{ {
public: public:
//! \brief STL compatibility //! STL compatibility
//! @{ //! @{
typedef T key_type; typedef T key_type;
typedef T value_type; typedef T value_type;
@@ -76,201 +76,133 @@ namespace BlackMisc
typedef intptr_t size_type; typedef intptr_t size_type;
//! @} //! @}
/*! //! Default constructor.
* \brief Default constructor.
*/
CCollection() : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>())) {} CCollection() : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>())) {}
/*! //! Initializer list constructor.
* \brief Initializer list constructor.
*/
CCollection(std::initializer_list<T> il) : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>(il))) {} CCollection(std::initializer_list<T> il) : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>(il))) {}
/*! //! Copy constructor.
* \brief Copy constructor.
*/
CCollection(const CCollection &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {} CCollection(const CCollection &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {}
/*! //! Constructor from QList.
* \brief Constructor from QList.
*/
CCollection(const QList<T> &list) : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>(list))) {} CCollection(const QList<T> &list) : m_pimpl(new Pimpl<QOrderedSet<T>>(QOrderedSet<T>(list))) {}
/*! //! Move constructor.
* \brief Move constructor.
*/
CCollection(CCollection &&other) noexcept(std::is_nothrow_move_constructible<T>::value) : m_pimpl(other.m_pimpl.take()) {} CCollection(CCollection &&other) noexcept(std::is_nothrow_move_constructible<T>::value) : m_pimpl(other.m_pimpl.take()) {}
/*! //! Copy assignment.
* \brief Copy assignment.
*/
CCollection &operator =(const CCollection &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; } CCollection &operator =(const CCollection &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; }
/*! //! Move assignment.
* \brief Move assignment.
*/
CCollection &operator =(CCollection && other) noexcept(std::is_nothrow_move_assignable<T>::value) { m_pimpl.reset(other.m_pimpl.take()); return *this; } CCollection &operator =(CCollection && other) noexcept(std::is_nothrow_move_assignable<T>::value) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
/*! //! Create a new collection with a specific implementation type.
* \brief Create a new collection with a specific implementation type. //! \tparam C Becomes the collection's implementation type.
* \tparam C Becomes the collection's implementation type. //! \param c Initial value for the collection; default is empty, but it could contain elements if desired. The value is copied.
* \param c Initial value for the collection; default is empty, but it could contain elements if desired. The value is copied.
*/
template <class C> static CCollection fromImpl(C c = C()) { return CCollection(new Pimpl<C>(std::move(c))); } template <class C> static CCollection fromImpl(C c = C()) { return CCollection(new Pimpl<C>(std::move(c))); }
/*! //! Change the implementation type but keep all the same elements, by moving them into the new implementation.
* \brief Change the implementation type but keep all the same elements, by moving them into the new implementation. //! \tparam C Becomes the collection's new implementation type.
* \tparam C Becomes the collection's new implementation type.
*/
template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); } template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); }
/*! //! Like changeImpl, but uses the implementation type of another collection.
* \brief Like changeImpl, but uses the implementation type of another collection. //! \pre The other collection must be initialized.
* \pre The other collection must be initialized.
*/
void useImplOf(const CCollection &other) { CCollection c(other.pimpl()->cloneEmpty()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); } void useImplOf(const CCollection &other) { CCollection c(other.pimpl()->cloneEmpty()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); }
/*! //! Returns iterator at the beginning of the collection.
* \brief Returns iterator at the beginning of the collection.
*/
iterator begin() { return pimpl() ? pimpl()->begin() : iterator(); } iterator begin() { return pimpl() ? pimpl()->begin() : iterator(); }
/*! //! Returns iterator at the beginning of the collection.
* \brief Returns iterator at the beginning of the collection.
*/
const_iterator begin() const { return pimpl() ? pimpl()->begin() : const_iterator(); } const_iterator begin() const { return pimpl() ? pimpl()->begin() : const_iterator(); }
/*! //! Returns iterator at the beginning of the collection.
* \brief Returns iterator at the beginning of the collection.
*/
const_iterator cbegin() const { return pimpl() ? pimpl()->cbegin() : const_iterator(); } const_iterator cbegin() const { return pimpl() ? pimpl()->cbegin() : const_iterator(); }
/*! //! Returns iterator one past the end of the collection.
* \brief Returns iterator one past the end of the collection.
*/
iterator end() { return pimpl() ? pimpl()->end() : iterator(); } iterator end() { return pimpl() ? pimpl()->end() : iterator(); }
/*! //! Returns const 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(); } const_iterator end() const { return pimpl() ? pimpl()->end() : const_iterator(); }
/*! //! Returns const 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(); } const_iterator cend() const { return pimpl() ? pimpl()->cend() : const_iterator(); }
/*! //! Swap this collection with another.
* \brief Swap this collection with another.
*/
void swap(CCollection &other) noexcept { m_pimpl.swap(other.m_pimpl); } void swap(CCollection &other) noexcept { m_pimpl.swap(other.m_pimpl); }
/*! //! Returns number of elements in the collection.
* \brief Returns number of elements in the collection.
*/
size_type size() const { return pimpl() ? pimpl()->size() : 0; } size_type size() const { return pimpl() ? pimpl()->size() : 0; }
/*! //! Returns true if the collection is empty.
* \brief Returns true if the collection is empty.
*/
bool empty() const { return pimpl() ? pimpl()->empty() : true; } bool empty() const { return pimpl() ? pimpl()->empty() : true; }
/*! //! Synonym for empty.
* \brief Synonym for empty.
*/
bool isEmpty() const { return empty(); } bool isEmpty() const { return empty(); }
/*! //! Removes all elements in the collection.
* \brief Removes all elements in the collection.
*/
void clear() { if (pimpl()) pimpl()->clear(); } void clear() { if (pimpl()) pimpl()->clear(); }
/*! //! For compatibility with std::inserter.
* \brief For compatibility with std::inserter. //! \param hint Ignored.
* \param hint Ignored. //! \param value The value to insert.
* \param value The value to insert. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator insert(const_iterator hint, const T &value) { Q_UNUSED(hint); return insert(value); } iterator insert(const_iterator hint, const T &value) { Q_UNUSED(hint); return insert(value); }
/*! //! For compatibility with std::inserter.
* \brief For compatibility with std::inserter. //! \param hint Ignored.
* \param hint Ignored. //! \param value The value to move in.
* \param value The value to move in. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator insert(const_iterator hint, T &&value) { Q_UNUSED(hint); return insert(std::move(value)); } iterator insert(const_iterator hint, T &&value) { Q_UNUSED(hint); return insert(std::move(value)); }
/*! //! Inserts an element into the collection.
* \brief Inserts an element into the collection. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator insert(const T &value) { Q_ASSERT(pimpl()); return pimpl()->insert(value); } iterator insert(const T &value) { Q_ASSERT(pimpl()); return pimpl()->insert(value); }
/*! //! Moves an element into the collection.
* \brief Moves an element into the collection. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator insert(T &&value) { Q_ASSERT(pimpl()); return pimpl()->insert(std::move(value)); } iterator insert(T &&value) { Q_ASSERT(pimpl()); return pimpl()->insert(std::move(value)); }
/*! //! Inserts all elements from another collection into this collection.
* \brief Inserts all elements from another collection into this collection. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
void insert(const CCollection &other) { std::copy(other.begin(), other.end(), std::inserter(*this, begin())); } void insert(const CCollection &other) { std::copy(other.begin(), other.end(), std::inserter(*this, begin())); }
/*! //! Inserts all elements from another collection into this collection.
* \brief Inserts all elements from another collection into this collection. //! This version moves elements instead of copying.
* This version moves elements instead of copying. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
void insert(CCollection &&other) { std::move(other.begin(), other.end(), std::inserter(*this, begin())); } void insert(CCollection &&other) { std::move(other.begin(), other.end(), std::inserter(*this, begin())); }
/*! //! Appends all elements from a range at the end of this collection.
* \brief Appends all elements from a range at the end of this collection. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
template <typename I> template <typename I>
void insert(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); } void insert(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); }
/*! //! Synonym for insert.
* \brief Synonym for insert. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator push_back(const T &value) { return insert(value); } iterator push_back(const T &value) { return insert(value); }
/*! //! Synonym for insert.
* \brief Synonym for insert. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator push_back(T &&value) { return insert(std::move(value)); } iterator push_back(T &&value) { return insert(std::move(value)); }
/*! //! Synonym for insert.
* \brief Synonym for insert. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
void push_back(const CCollection &other) { insert(other); } void push_back(const CCollection &other) { insert(other); }
/*! //! Synonym for insert.
* \brief Synonym for insert. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
void push_back(CCollection &&other) { insert(std::move(other)); } void push_back(CCollection &&other) { insert(std::move(other)); }
/*! //! Synonym for insert.
* \brief Synonym for insert. //! \pre This collection must be initialized.
* \pre This collection must be initialized.
*/
template <typename I> template <typename I>
void push_back(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); } void push_back(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); }
/*! //! Returns a collection which is the union of this collection and another container.
* \brief Returns a collection which is the union of this collection and another container.
*/
template <class C> template <class C>
CCollection makeUnion(const C &other) const CCollection makeUnion(const C &other) const
{ {
@@ -279,9 +211,7 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Returns a collection which is the intersection of this collection and another.
* \brief Returns a collection which is the intersection of this collection and another.
*/
template <class C> template <class C>
CCollection intersection(const C &other) const CCollection intersection(const C &other) const
{ {
@@ -290,9 +220,7 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Returns a collection which contains all the elements from this collection which are not in the other collection.
* \brief Returns a collection which contains all the elements from this collection which are not in the other collection.
*/
template <class C> template <class C>
CCollection difference(const C &other) const CCollection difference(const C &other) const
{ {
@@ -301,52 +229,38 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Remove the element pointed to by the given iterator.
* \brief Remove the element pointed to by the given iterator. //! \return An iterator to the position of the next element after the one removed.
* \return An iterator to the position of the next element after the one removed. //! \pre The collection must be initialized.
* \pre The collection must be initialized.
*/
iterator erase(iterator pos) { Q_ASSERT(pimpl()); return pimpl()->erase(pos); } iterator erase(iterator pos) { Q_ASSERT(pimpl()); return pimpl()->erase(pos); }
/*! //! Remove the range of elements between two iterators.
* \brief Remove the range of elements between two iterators. //! \return An iterator to the position of the next element after the one removed.
* \return An iterator to the position of the next element after the one removed. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
iterator erase(iterator it1, iterator it2) { Q_ASSERT(pimpl()); return pimpl()->erase(it1, it2); } iterator erase(iterator it1, iterator it2) { Q_ASSERT(pimpl()); return pimpl()->erase(it1, it2); }
/*! //! Efficient find method using the find of the implementation container. Typically O(log n).
* \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.
* \return An iterator to the position of the found element, or the end iterator if not found. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized. //! \warning Take care that the returned non-const iterator is not compared with a const iterator.
* \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); } iterator find(const T &value) { Q_ASSERT(pimpl()); return pimpl()->find(value); }
/*! //! Efficient find method using the find of the implementation container. Typically O(log n).
* \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.
* \return An iterator to the position of the found element, or the end iterator if not found. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
const_iterator find(const T &value) const { Q_ASSERT(pimpl()); return pimpl()->find(value); } const_iterator find(const T &value) const { Q_ASSERT(pimpl()); return pimpl()->find(value); }
/*! //! Efficient remove using the find and erase of the implementation container. Typically O(log n).
* \brief Efficient remove using the find and erase of the implementation container. Typically O(log n). //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void remove(const T &object) { auto it = find(object); if (it != end()) { erase(it); } } void remove(const T &object) { auto it = find(object); if (it != end()) { erase(it); } }
/*! //! Removes from this collection all of the elements of another collection.
* \brief Removes from this collection all of the elements of another collection. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
void remove(const CCollection &other) { *this = CCollection(*this).difference(other); } void remove(const CCollection &other) { *this = CCollection(*this).difference(other); }
/*! //! Remove elements for which a given predicate returns true.
* \brief Remove elements for which a given predicate returns true. //! \pre The collection must be initialized.
* \pre The collection must be initialized. //! \return The number of elements removed.
* \return The number of elements removed.
*/
template <class Predicate> template <class Predicate>
int removeIf(Predicate p) int removeIf(Predicate p)
{ {
@@ -367,21 +281,15 @@ namespace BlackMisc
return CCollection::CContainerBase::removeIf(k0, v0, keysValues...); return CCollection::CContainerBase::removeIf(k0, v0, keysValues...);
} }
/*! //! Test for equality.
* \brief Test for equality.
*/
bool operator ==(const CCollection &other) const { return *pimpl() == *other.pimpl(); } bool operator ==(const CCollection &other) const { return *pimpl() == *other.pimpl(); }
/*! //! Test for inequality.
* \brief Test for inequality.
*/
bool operator !=(const CCollection &other) const { return !(*this == other); } bool operator !=(const CCollection &other) const { return !(*this == other); }
/*! //! Return an opaque pointer to the implementation container.
* \brief Return an opaque pointer to the implementation container. //! \details Can be useful in unusual debugging situations.
* \details Can be useful in unusual debugging situations. //! \warning Not for general use.
* \warning Not for general use.
*/
void *getImpl() { return pimpl() ? pimpl()->impl() : nullptr; } void *getImpl() { return pimpl() ? pimpl()->impl() : nullptr; }
private: private:

View File

@@ -47,7 +47,7 @@ namespace BlackMisc
}; };
/*! /*!
* \brief Base class for CCollection and CSequence adding mutating operations and CValueObject facility on top of CRangeBase. * Base class for CCollection and CSequence adding mutating operations and CValueObject facility on top of CRangeBase.
*/ */
template <template <class> class C, class T, class CIt> template <template <class> class C, class T, class CIt>
class CContainerBase : class CContainerBase :
@@ -73,11 +73,9 @@ namespace BlackMisc
} }
/*! //! Return a new container of a different type, containing the same elements as this one.
* \brief Return a new container of a different type, containing the same elements as this one. //! \tparam Other the type of the new container.
* \tparam Other the type of the new container. //! \param other an optional initial value for the new container; will be copied.
* \param other an optional initial value for the new container; will be copied.
*/
template <template <class> class Other> template <template <class> class Other>
Other<T> to(Other<T> other = Other<T>()) const Other<T> to(Other<T> other = Other<T>()) const
{ {
@@ -85,13 +83,11 @@ namespace BlackMisc
return other; return other;
} }
/*! //! Remove elements matching some particular key/value pair(s).
* \brief Remove elements matching some particular key/value pair(s). //! \param k0 A pointer to a member function of T.
* \param k0 A pointer to a member function of T. //! \param v0 A value to compare against the value returned by k0.
* \param v0 A value to compare against the value returned by k0. //! \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }.
* \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }. //! \return The number of elements removed.
* \return The number of elements removed.
*/
template <class K0, class V0, class... KeysValues> template <class K0, class V0, class... KeysValues>
int removeIf(K0 k0, V0 v0, KeysValues... keysValues) int removeIf(K0 k0, V0 v0, KeysValues... keysValues)
{ {

View File

@@ -83,11 +83,15 @@ namespace BlackMisc
} // namespace Private } // namespace Private
//! Trait to select the appropriate default associative container type depending on what the key type supports /*!
* Trait to select the appropriate default associative container type depending on what the key type supports.
*/
template <typename K, typename V> template <typename K, typename V>
using DefaultAssociativeType = typename Private::AssociativityTraits<ModelsQHashKey<K>::value, ModelsQMapKey<K>::value>::template DefaultType<K, V>; using DefaultAssociativeType = typename Private::AssociativityTraits<ModelsQHashKey<K>::value, ModelsQMapKey<K>::value>::template DefaultType<K, V>;
//! Associative container with value semantics, chooses a sensible default implementation container type /*!
* Associative container with value semantics, chooses a sensible default implementation container type.
*/
template<class Key, class Value, template <class...> class Impl = DefaultAssociativeType> template<class Key, class Value, template <class...> class Impl = DefaultAssociativeType>
class CDictionary : class CDictionary :
public Mixin::DBusOperators<CDictionary<Key, Value, Impl>>, public Mixin::DBusOperators<CDictionary<Key, Value, Impl>>,
@@ -131,19 +135,15 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Return a copy containing only those elements which key matches a particular pair.
* \brief Return a copy containing only those elements which key matches a particular pair. //! \param pairs Pairs of { pointer to member function of Value, return value to compare it against }.
* \param pairs Pairs of { pointer to member function of Value, return value to compare it against }.
*/
template <class... Pairs > template <class... Pairs >
CDictionary findKeyBy(Pairs... pairs) const CDictionary findKeyBy(Pairs... pairs) const
{ {
return findKeyBy(BlackMisc::Predicates::MemberEqual(pairs...)); return findKeyBy(BlackMisc::Predicates::MemberEqual(pairs...));
} }
/*! //! Return a copy containing only those elements for which a given predicate returns true.
* \brief Return a copy containing only those elements for which a given predicate returns true.
*/
template <class Predicate> template <class Predicate>
CDictionary findValueBy(Predicate p) const CDictionary findValueBy(Predicate p) const
{ {
@@ -156,19 +156,15 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Return a copy containing only those elements which value matches a particular pair.
* \brief Return a copy containing only those elements which value matches a particular pair. //! \param pairs Pairs of { pointer to member function of Value, return value to compare it against }.
* \param pairs Pairs of { pointer to member function of Value, return value to compare it against }.
*/
template <class... Pairs > template <class... Pairs >
CDictionary findValueBy(Pairs... pairs) const CDictionary findValueBy(Pairs... pairs) const
{ {
return findValueBy(BlackMisc::Predicates::MemberEqual(pairs...)); return findValueBy(BlackMisc::Predicates::MemberEqual(pairs...));
} }
/*! //! Return true if there is an element for which a given predicate returns true.
* \brief Return true if there is an element for which a given predicate returns true.
*/
template <class Predicate> template <class Predicate>
bool containsByKey(Predicate p) const bool containsByKey(Predicate p) const
{ {
@@ -318,25 +314,16 @@ namespace BlackMisc
//! Returns const iterator at the end of the dictionary //! Returns const iterator at the end of the dictionary
const_iterator constEnd() const { return m_impl.constEnd(); } const_iterator constEnd() const { return m_impl.constEnd(); }
/*! //! Returns an const iterator pointing to the item with the key.
* \brief Returns an const iterator pointing to the item with the key. //! \return If key is not found, the function returns constEnd()
* \param key
* \return If key is not found, the function returns constEnd()
*/
const_iterator constFind (const Key &key) const { return m_impl.constFind(key); } const_iterator constFind (const Key &key) const { return m_impl.constFind(key); }
/*! //! Returns an const iterator pointing to the item with the key.
* \brief Returns an const iterator pointing to the item with the key. //! \return If key is not found, the function returns end()
* \param key
* \return If key is not found, the function returns end()
*/
const_iterator find(const Key & key) const { return m_impl.find(key); } const_iterator find(const Key & key) const { return m_impl.find(key); }
/*! //! Returns an iterator pointing to the item with the key.
* \brief Returns an iterator pointing to the item with the key. //! \return If key is not found, the function returns end()
* \param key
* \return If key is not found, the function returns end()
*/
iterator find(const Key &key) { return m_impl.find(key); } iterator find(const Key &key) { return m_impl.find(key); }
//! Returns true if dictionary contains an item with key, otherwise false //! Returns true if dictionary contains an item with key, otherwise false
@@ -402,20 +389,12 @@ namespace BlackMisc
//! Return reference to the internal implementation object. //! Return reference to the internal implementation object.
friend const impl_type &implementationOf(const CDictionary &dict) { return dict.m_impl; } friend const impl_type &implementationOf(const CDictionary &dict) { return dict.m_impl; }
/*! //! Access an element by its key.
* \brief Access an element by its key. //! \note If dictionary does not contain any item with key, a default constructed value will be inserted.
* \note
* If dictionary does not contain any item with key, a default constructed
* value will be inserted
*/
Value &operator [](const Key &key) { return m_impl[key]; } Value &operator [](const Key &key) { return m_impl[key]; }
/*! //! Access an element by its key.
* \brief Access an element by its key. //! \note If dictionary does not contain any item with key, a default constructed value will be inserted.
* \note
* If dictionary does not contain any item with key, a default constructed
* value will be inserted
*/
const Value operator [](const Key &key) const { return m_impl[key]; } const Value operator [](const Key &key) const { return m_impl[key]; }
//! Test for equality. //! Test for equality.
@@ -454,15 +433,21 @@ namespace BlackMisc
Impl<Key,Value> m_impl; Impl<Key,Value> m_impl;
}; };
//! Identity function for API consistency with CDictionary::implementationOf. /*!
* Identity function for API consistency with CDictionary::implementationOf.
*/
template <class Key, class Value> template <class Key, class Value>
QMap<Key, Value> &implementationOf(QMap<Key, Value> &dict) { return dict; } QMap<Key, Value> &implementationOf(QMap<Key, Value> &dict) { return dict; }
//! Identity function for API consistency with CDictionary::implementationOf. /*!
* Identity function for API consistency with CDictionary::implementationOf.
*/
template <class Key, class Value> template <class Key, class Value>
const QMap<Key, Value> &implementationOf(const QMap<Key, Value> &dict) { return dict; } const QMap<Key, Value> &implementationOf(const QMap<Key, Value> &dict) { return dict; }
//! Call a functor for each {key,value1,value2} triple in the keywise intersection of two maps. /*!
* Call a functor for each {key,value1,value2} triple in the keywise intersection of two maps.
*/
template <class Map1, class Map2, class F> template <class Map1, class Map2, class F>
void forEachIntersection(const Map1 &map1, const Map2 &map2, F functor) void forEachIntersection(const Map1 &map1, const Map2 &map2, F functor)
{ {
@@ -516,7 +501,6 @@ namespace BlackMisc
* Calculate a single hash value based on a list of individual hash values. * Calculate a single hash value based on a list of individual hash values.
* \param values * \param values
* \param className Will be hashed and used as an additional value in the list. * \param className Will be hashed and used as an additional value in the list.
* \return
*/ */
//! @{ //! @{
BLACKMISC_EXPORT uint calculateHash(const QList<uint> &values, const char *className); BLACKMISC_EXPORT uint calculateHash(const QList<uint> &values, const char *className);

View File

@@ -91,7 +91,7 @@ namespace BlackMisc
} //namespace Private } //namespace Private
/*! /*!
* \brief Predicate which tests whether some member functions return some values. * Predicate which tests whether some member functions return some values.
* \param vs Pairs of { pointer to member function of T, value to compare it against }. * \param vs Pairs of { pointer to member function of T, value to compare it against }.
* \return A unary functor whose operator() which will perform the actual test. * \return A unary functor whose operator() which will perform the actual test.
*/ */
@@ -102,7 +102,7 @@ namespace BlackMisc
} }
/*! /*!
* \brief Predicate which compares the return values of some member functions of two objects. * Predicate which compares the return values of some member functions of two objects.
* \param vs Pointers to member functions of T. * \param vs Pointers to member functions of T.
* \return A binary functor whose operator() which will perform the actual test. * \return A binary functor whose operator() which will perform the actual test.
*/ */

View File

@@ -52,78 +52,58 @@ namespace BlackMisc
using const_reference = typename std::iterator_traits<CIt>::reference; using const_reference = typename std::iterator_traits<CIt>::reference;
public: public:
/*! //! Return a new container generated by applying some transformation function to all elements of this one.
* Return a new container generated by applying some transformation function to all elements of this one.
*/
template <class F> template <class F>
inline auto transform(F function) const inline auto transform(F function) const
-> CRange<Iterators::TransformIterator<CIt, F>>; -> CRange<Iterators::TransformIterator<CIt, F>>;
/*! //! Return a copy containing only those elements for which a given predicate returns true.
* \brief Return a copy containing only those elements for which a given predicate returns true.
*/
template <class Predicate> template <class Predicate>
inline auto findBy(Predicate p) const inline auto findBy(Predicate p) const
-> CRange<Iterators::ConditionalIterator<CIt, Predicate>>; -> CRange<Iterators::ConditionalIterator<CIt, Predicate>>;
/*! //! Return a copy containing only those elements matching some particular key/value pair(s).
* \brief Return a copy containing only those elements matching some particular key/value pair(s). //! \param k0 A pointer to a member function of T.
* \param k0 A pointer to a member function of T. //! \param v0 A value to compare against the value returned by k0.
* \param v0 A value to compare against the value returned by k0. //! \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }.
* \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }.
*/
template <class K0, class V0, class... KeysValues> template <class K0, class V0, class... KeysValues>
inline auto findBy(K0 k0, V0 v0, KeysValues... keysValues) const inline auto findBy(K0 k0, V0 v0, KeysValues... keysValues) const
-> CRange<Iterators::ConditionalIterator<CIt, decltype(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...))>>; -> CRange<Iterators::ConditionalIterator<CIt, decltype(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...))>>;
/*! //! Return a reference to the first element for which a given predicate returns true. Undefined if there is none.
* Return a reference to the first element for which a given predicate returns true. Undefined if there is none.
*/
template <class Predicate> template <class Predicate>
const_reference findFirstBy(Predicate p) const { return findBy(p).front(); } const_reference findFirstBy(Predicate p) const { return findBy(p).front(); }
/*! //! Return a reference to the first element matching some particular key/value pair(s). Undefined if there is none.
* Return a reference to the first element matching some particular key/value pair(s). Undefined if there is none.
*/
template <class K, class V> template <class K, class V>
const_reference findFirstBy(K key, V value) const { return findBy(key, value).front(); } const_reference findFirstBy(K key, V value) const { return findBy(key, value).front(); }
/*! //! Return a copy of the first element for which a given predicate returns true, or a default value if there is none.
* Return a copy of the first element for which a given predicate returns true, or a default value if there is none.
*/
template <class Predicate> template <class Predicate>
value_type findFirstByOrDefault(Predicate p, const value_type &def = value_type{}) const { return findBy(p).frontOrDefault(def); } value_type findFirstByOrDefault(Predicate p, const value_type &def = value_type{}) const { return findBy(p).frontOrDefault(def); }
/*! //! Return a copy of the first element matching some particular key/value pair(s), or a default value if there is none.
* Return a copy of the first element matching some particular key/value pair(s), or a default value if there is none.
*/
template <class K, class V> template <class K, class V>
value_type findFirstByOrDefault(K key, V value, const value_type &def = value_type{}) const { return findBy(key, value).frontOrDefault(def); } value_type findFirstByOrDefault(K key, V value, const value_type &def = value_type{}) const { return findBy(key, value).frontOrDefault(def); }
/*! //! Return true if there is an element for which a given predicate returns true.
* \brief Return true if there is an element for which a given predicate returns true.
*/
template <class Predicate> template <class Predicate>
bool containsBy(Predicate p) const bool containsBy(Predicate p) const
{ {
return std::any_of(derived().cbegin(), derived().cend(), p); return std::any_of(derived().cbegin(), derived().cend(), p);
} }
/*! //! Return true if there is an element equal to given object. Uses the most efficient implementation available in the derived container.
* \brief Return true if there is an element equal to given object. Uses the most efficient implementation available in the derived container.
*/
template <class T> template <class T>
bool contains(const T &object) const bool contains(const T &object) const
{ {
return derived().find(object) != derived().cend(); return derived().find(object) != derived().cend();
} }
/*! //! Return a copy containing only those elements matching some particular key/value pair(s).
* \brief Return a copy containing only those elements matching some particular key/value pair(s). //! \param k0 A pointer to a member function of T.
* \param k0 A pointer to a member function of T. //! \param v0 A value to compare against the value returned by k0.
* \param v0 A value to compare against the value returned by k0. //! \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }.
* \param keysValues Zero or more additional pairs of { pointer to member function of T, value to compare it against }.
*/
template <class K0, class V0, class... KeysValues> template <class K0, class V0, class... KeysValues>
bool contains(K0 k0, V0 v0, KeysValues... keysValues) const bool contains(K0 k0, V0 v0, KeysValues... keysValues) const
{ {

View File

@@ -26,7 +26,7 @@ namespace BlackMisc
{ {
/*! /*!
* \brief Generic type-erased sequential container with value semantics. * Generic type-erased sequential container with value semantics.
* \tparam T the type of elements contained. * \tparam T the type of elements contained.
* *
* Can take any suitable container class as its implementation at runtime. * Can take any suitable container class as its implementation at runtime.
@@ -37,7 +37,7 @@ namespace BlackMisc
public Mixin::Icon<CSequence<T>> public Mixin::Icon<CSequence<T>>
{ {
public: public:
//! \brief STL compatibility //! STL compatibility
//! @{ //! @{
typedef T key_type; typedef T key_type;
typedef T value_type; typedef T value_type;
@@ -51,307 +51,201 @@ namespace BlackMisc
typedef intptr_t size_type; typedef intptr_t size_type;
//! @} //! @}
/*! //! Default constructor.
* \brief Default constructor.
*/
CSequence() : m_pimpl(new Pimpl<QList<T>>(QList<T>())) {} CSequence() : m_pimpl(new Pimpl<QList<T>>(QList<T>())) {}
/*! //! Initializer list constructor.
* \brief Initializer list constructor.
*/
CSequence(std::initializer_list<T> il) : m_pimpl(new Pimpl<QList<T>>(QList<T>(il))) {} CSequence(std::initializer_list<T> il) : m_pimpl(new Pimpl<QList<T>>(QList<T>(il))) {}
/*! //! By QList of type T.
* \brief By QList of type T.
*/
CSequence(const QList<T> &list) : m_pimpl(new Pimpl<QList<T>>(QList<T>(list))) {} CSequence(const QList<T> &list) : m_pimpl(new Pimpl<QList<T>>(QList<T>(list))) {}
/*! //! Copy constructor.
* \brief Copy constructor.
*/
CSequence(const CSequence &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {} CSequence(const CSequence &other) : m_pimpl(other.pimpl() ? other.pimpl()->clone() : nullptr) {}
/*! //! Move constructor.
* \brief Move constructor.
*/
CSequence(CSequence &&other) noexcept(std::is_nothrow_move_constructible<T>::value) : m_pimpl(other.m_pimpl.take()) {} CSequence(CSequence &&other) noexcept(std::is_nothrow_move_constructible<T>::value) : m_pimpl(other.m_pimpl.take()) {}
/*! //! Copy assignment.
* \brief Copy assignment.
*/
CSequence &operator =(const CSequence &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; } CSequence &operator =(const CSequence &other) { m_pimpl.reset(other.pimpl() ? other.pimpl()->clone() : nullptr); return *this; }
/*! //! Move assignment.
* \brief Move assignment.
*/
CSequence &operator =(CSequence && other) noexcept(std::is_nothrow_move_assignable<T>::value) { m_pimpl.reset(other.m_pimpl.take()); return *this; } CSequence &operator =(CSequence && other) noexcept(std::is_nothrow_move_assignable<T>::value) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
/*! //! Create a new sequence with a specific implementation type.
* \brief Create a new sequence with a specific implementation type. //! \tparam C Becomes the sequence's implementation type.
* \tparam C Becomes the sequence's implementation type. //! \param c Initial value for the sequence; default is empty, but it could contain elements if desired. The value is copied.
* \param c Initial value for the sequence; default is empty, but it could contain elements if desired. The value is copied.
*/
template <class C> static CSequence fromImpl(C c = C()) { return CSequence(new Pimpl<C>(std::move(c))); } template <class C> static CSequence fromImpl(C c = C()) { return CSequence(new Pimpl<C>(std::move(c))); }
/*! //! Change the implementation type but keep all the same elements, by moving them into the new implementation.
* \brief Change the implementation type but keep all the same elements, by moving them into the new implementation. //! \tparam C Becomes the sequence's new implementation type.
* \tparam C Becomes the sequence's new implementation type.
*/
template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); } template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); }
/*! //! Like changeImpl, but uses the implementation type of another sequence.
* \brief Like changeImpl, but uses the implementation type of another sequence. //! \pre The other sequence must be initialized.
* \pre The other sequence must be initialized.
*/
void useImplOf(const CSequence &other) { CSequence c(other.pimpl()->cloneEmpty()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); } void useImplOf(const CSequence &other) { CSequence c(other.pimpl()->cloneEmpty()); std::move(begin(), end(), std::inserter(c, c.begin())); *this = std::move(c); }
/*! //! Returns iterator at the beginning of the sequence.
* \brief Returns iterator at the beginning of the sequence.
*/
iterator begin() { return pimpl() ? pimpl()->begin() : iterator(); } iterator begin() { return pimpl() ? pimpl()->begin() : iterator(); }
/*! //! Returns const iterator at the beginning of the sequence.
* \brief Returns const iterator at the beginning of the sequence.
*/
const_iterator begin() const { return pimpl() ? pimpl()->begin() : const_iterator(); } const_iterator begin() const { return pimpl() ? pimpl()->begin() : const_iterator(); }
/*! //! Returns const iterator at the beginning of the sequence.
* \brief Returns const iterator at the beginning of the sequence.
*/
const_iterator cbegin() const { return pimpl() ? pimpl()->cbegin() : const_iterator(); } const_iterator cbegin() const { return pimpl() ? pimpl()->cbegin() : const_iterator(); }
/*! //! Returns iterator one past the end of the sequence.
* \brief Returns iterator one past the end of the sequence.
*/
iterator end() { return pimpl() ? pimpl()->end() : iterator(); } iterator end() { return pimpl() ? pimpl()->end() : iterator(); }
/*! //! Returns const iterator one past the end of the sequence.
* \brief Returns const iterator one past the end of the sequence.
*/
const_iterator end() const { return pimpl() ? pimpl()->end() : const_iterator(); } const_iterator end() const { return pimpl() ? pimpl()->end() : const_iterator(); }
/*! //! Returns const iterator one past the end of the sequence.
* \brief Returns const iterator one past the end of the sequence.
*/
const_iterator cend() const { return pimpl() ? pimpl()->cend() : const_iterator(); } const_iterator cend() const { return pimpl() ? pimpl()->cend() : const_iterator(); }
/*! //! Swap this sequence with another.
* \brief Swap this sequence with another.
*/
void swap(CSequence &other) noexcept { m_pimpl.swap(other.m_pimpl); } void swap(CSequence &other) noexcept { m_pimpl.swap(other.m_pimpl); }
/*! //! Access an element by its index.
* \brief Access an element by its index. //! \pre The sequence must be initialized and the index in bounds.
* \pre The sequence must be initialized and the index in bounds.
*/
reference operator [](size_type index) { Q_ASSERT(pimpl()); return pimpl()->operator [](index); } reference operator [](size_type index) { Q_ASSERT(pimpl()); return pimpl()->operator [](index); }
/*! //! Access an element by its index.
* \brief Access an element by its index. //! \pre The sequence must be initialized and the index in bounds.
* \pre The sequence must be initialized and the index in bounds.
*/
const_reference operator [](size_type index) const { Q_ASSERT(pimpl()); return pimpl()->operator [](index); } const_reference operator [](size_type index) const { Q_ASSERT(pimpl()); return pimpl()->operator [](index); }
/*! //! Access the first element.
* \brief Access the first element. //! \pre The sequence must not be empty.
* \pre The sequence must not be empty.
*/
reference front() { Q_ASSERT(!empty()); return pimpl()->front(); } reference front() { Q_ASSERT(!empty()); return pimpl()->front(); }
/*! //! Access the first element.
* \brief Access the first element. //! \pre The sequence must not be empty.
* \pre The sequence must not be empty.
*/
const_reference front() const { Q_ASSERT(!empty()); return pimpl()->front(); } const_reference front() const { Q_ASSERT(!empty()); return pimpl()->front(); }
/*! //! Access the first element, or a default-initialized value if the sequence is empty.
* \brief Access the first element, or a default-initialized value if the sequence is empty.
*/
const_reference frontOrDefault() const { static const value_type def {}; return empty() ? def : front(); } const_reference frontOrDefault() const { static const value_type def {}; return empty() ? def : front(); }
/*! //! Access the first element, or a default-initialized value if the sequence is empty.
* \brief Access the first element, or a default-initialized value if the sequence is empty.
*/
value_type frontOrDefault(value_type def) const { return empty() ? def : front(); } value_type frontOrDefault(value_type def) const { return empty() ? def : front(); }
/*! //! Access the last element.
* \brief Access the last element. //! \pre The sequence must not be empty.
* \pre The sequence must not be empty.
*/
reference back() { Q_ASSERT(!empty()); return pimpl()->back(); } reference back() { Q_ASSERT(!empty()); return pimpl()->back(); }
/*! //! Access the last element.
* \brief Access the last element. //! \pre The sequence must not be empty.
* \pre The sequence must not be empty.
*/
const_reference back() const { Q_ASSERT(!empty()); return pimpl()->back(); } const_reference back() const { Q_ASSERT(!empty()); return pimpl()->back(); }
/*! //! Access the last element, or a default value if the sequence is empty.
* \brief Access the last element, or a default value if the sequence is empty.
*/
const_reference backOrDefault() const { static const value_type def {}; return empty() ? def : back(); } const_reference backOrDefault() const { static const value_type def {}; return empty() ? def : back(); }
/*! //! Access the last element, or a default value if the sequence is empty.
* \brief Access the last element, or a default value if the sequence is empty.
*/
value_type backOrDefault(value_type def) const { return empty() ? def : back(); } value_type backOrDefault(value_type def) const { return empty() ? def : back(); }
/*! //! Returns number of elements in the sequence.
* \brief Returns number of elements in the sequence.
*/
size_type size() const { return pimpl() ? pimpl()->size() : 0; } size_type size() const { return pimpl() ? pimpl()->size() : 0; }
/*! //! Returns true if the sequence is empty.
* \brief Returns true if the sequence is empty.
*/
bool empty() const { return pimpl() ? pimpl()->empty() : true; } bool empty() const { return pimpl() ? pimpl()->empty() : true; }
/*! //! Synonym for empty.
* \brief Synonym for empty.
*/
bool isEmpty() const { return empty(); } bool isEmpty() const { return empty(); }
/*! //! Removes all elements in the sequence.
* \brief Removes all elements in the sequence.
*/
void clear() { if (pimpl()) pimpl()->clear(); } void clear() { if (pimpl()) pimpl()->clear(); }
/*! //! Changes the size of the sequence, if it is bigger than the given size.
* \brief Changes the size of the sequence, if it is bigger than the given size.
*/
void truncate(size_type maxSize) { if (size() > maxSize) { erase(begin() + maxSize, end()); } } void truncate(size_type maxSize) { if (size() > maxSize) { erase(begin() + maxSize, end()); } }
/*! //! Inserts an element into the sequence.
* \brief Inserts an element into the sequence. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
iterator insert(iterator before, const T &value) { Q_ASSERT(pimpl()); return pimpl()->insert(before, value); } iterator insert(iterator before, const T &value) { Q_ASSERT(pimpl()); return pimpl()->insert(before, value); }
/*! //! Moves an element into the sequence.
* \brief Moves an element into the sequence. //! \return An iterator to the position where value was inserted.
* \return An iterator to the position where value was inserted. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
iterator insert(iterator before, T &&value) { Q_ASSERT(pimpl()); return pimpl()->insert(before, std::move(value)); } iterator insert(iterator before, T &&value) { Q_ASSERT(pimpl()); return pimpl()->insert(before, std::move(value)); }
/*! //! Appends an element at the end of the sequence.
* \brief Appends an element at the end of the sequence. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void push_back(const T &value) { Q_ASSERT(pimpl()); pimpl()->push_back(value); } void push_back(const T &value) { Q_ASSERT(pimpl()); pimpl()->push_back(value); }
/*! //! Insert as first element.
* \brief Insert as first element. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void push_front(const T &value) { insert(begin(), value); } void push_front(const T &value) { insert(begin(), value); }
/*! //! Move-appends an element at the end of the sequence.
* \brief Move-appends an element at the end of the sequence. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void push_back(T &&value) { Q_ASSERT(pimpl()); pimpl()->push_back(std::move(value)); } void push_back(T &&value) { Q_ASSERT(pimpl()); pimpl()->push_back(std::move(value)); }
/*! //! Appends all elements from another sequence at the end of this sequence.
* \brief Appends all elements from another sequence at the end of this sequence. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
void push_back(const CSequence &other) { std::copy(other.begin(), other.end(), std::back_inserter(*this)); } void push_back(const CSequence &other) { std::copy(other.begin(), other.end(), std::back_inserter(*this)); }
/*! //! Appends all elements from another sequence at the end of this sequence.
* \brief Appends all elements from another sequence at the end of this sequence. //! This version moves elements instead of copying.
* This version moves elements instead of copying. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
void push_back(CSequence &&other) { std::move(other.begin(), other.end(), std::back_inserter(*this)); } void push_back(CSequence &&other) { std::move(other.begin(), other.end(), std::back_inserter(*this)); }
/*! //! Appends all elements from a range at the end of this sequence.
* \brief Appends all elements from a range at the end of this sequence. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
template <typename I> template <typename I>
void push_back(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); } void push_back(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); }
/*! //! Synonym for push_back.
* \brief Synonym for push_back. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void insert(const T &value) { push_back(value); } void insert(const T &value) { push_back(value); }
/*! //! Synonym for push_back.
* \brief Synonym for push_back. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void insert(T &&value) { push_back(std::move(value)); } void insert(T &&value) { push_back(std::move(value)); }
/*! //! Synonym for push_back.
* \brief Synonym for push_back. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void insert(const CSequence &other) { push_back(other); } void insert(const CSequence &other) { push_back(other); }
/*! //! Synonym for push_back.
* \brief Synonym for push_back. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void insert(CSequence &&other) { push_back(std::move(other)); } void insert(CSequence &&other) { push_back(std::move(other)); }
/*! //! Synonym for push_back.
* \brief Synonym for push_back. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
template <typename I> template <typename I>
void insert(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); } void insert(const CRange<I> &range) { std::copy(range.begin(), range.end(), std::back_inserter(*this)); }
/*! //! Concatenates two sequences and returns the result.
* \brief Concatenates two sequences and returns the result. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
CSequence join(const CSequence &other) const { CSequence copy(*this); copy.push_back(other); return copy; } CSequence join(const CSequence &other) const { CSequence copy(*this); copy.push_back(other); return copy; }
/*! //! Concatenates a sequence and a range and returns the result.
* \brief Concatenates a sequence and a range and returns the result. //! \pre This sequence must be initialized.
* \pre This sequence must be initialized.
*/
template <typename I> template <typename I>
CSequence join(const CRange<I> &range) const { CSequence copy(*this); copy.push_back(range); return copy; } CSequence join(const CRange<I> &range) const { CSequence copy(*this); copy.push_back(range); return copy; }
/*! //! Removes an element at the end of the sequence.
* \brief Removes an element at the end of the sequence. //! \pre The sequence must contain at least one element.
* \pre The sequence must contain at least one element.
*/
void pop_back() { Q_ASSERT(!empty()); pimpl()->pop_back(); } void pop_back() { Q_ASSERT(!empty()); pimpl()->pop_back(); }
/*! //! Remove the element pointed to by the given iterator.
* \brief Remove the element pointed to by the given iterator. //! \return An iterator to the position of the next element after the one removed.
* \return An iterator to the position of the next element after the one removed. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
iterator erase(iterator pos) { Q_ASSERT(pimpl()); return pimpl()->erase(pos); } iterator erase(iterator pos) { Q_ASSERT(pimpl()); return pimpl()->erase(pos); }
/*! //! Remove the range of elements between two iterators.
* \brief Remove the range of elements between two iterators. //! \return An iterator to the position of the next element after the one removed.
* \return An iterator to the position of the next element after the one removed. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
iterator erase(iterator it1, iterator it2) { Q_ASSERT(pimpl()); return pimpl()->erase(it1, it2); } iterator erase(iterator it1, iterator it2) { Q_ASSERT(pimpl()); return pimpl()->erase(it1, it2); }
/*! //! Return an iterator to the first element equal to the given object, or the end iterator if not found. O(n).
* \brief Return an iterator to the first element equal to the given object, or the end iterator if not found. O(n). //! \warning Take care that the returned non-const iterator is not compared with a const iterator.
* \warning Take care that the returned non-const iterator is not compared with a const iterator.
*/
iterator find(const T &object) { return std::find(begin(), end(), object); } iterator find(const T &object) { return std::find(begin(), end(), object); }
/*! //! Return an iterator to the first element equal to the given object, or the end iterator if not found. O(n).
* \brief Return an iterator to the first element equal to the given object, or the end iterator if not found. O(n).
*/
const_iterator find(const T &object) const { return std::find(cbegin(), cend(), object); } const_iterator find(const T &object) const { return std::find(cbegin(), cend(), object); }
/*! //! Modify by applying a value map to each element for which a given predicate returns true.
* \brief Modify by applying a value map to each element for which a given predicate returns true. //! \return The number of elements modified.
* \return The number of elements modified.
*/
template <class Predicate, class VariantMap> template <class Predicate, class VariantMap>
int applyIf(Predicate p, const VariantMap &newValues, bool skipEqualValues = false) int applyIf(Predicate p, const VariantMap &newValues, bool skipEqualValues = false)
{ {
@@ -363,25 +257,21 @@ namespace BlackMisc
return count; return count;
} }
/*! //! Modify by applying a value map to each element matching a particular key/value pair.
* \brief Modify by applying a value map to each element matching a particular key/value pair. //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param value1 Will be compared to the return value of key1.
* \param value1 Will be compared to the return value of key1. //! \param newValues Values from this map will be put into each matching element.
* \param newValues Values from this map will be put into each matching element. //! \param skipEqualValues Equal values will not be updated
* \param skipEqualValues Equal values will not be updated //! \return The number of elements modified.
* \return The number of elements modified.
*/
template <class K1, class V1, class VariantMap> template <class K1, class V1, class VariantMap>
int applyIf(K1 key1, V1 value1, const VariantMap &newValues, bool skipEqualValues = false) int applyIf(K1 key1, V1 value1, const VariantMap &newValues, bool skipEqualValues = false)
{ {
return applyIf(BlackMisc::Predicates::MemberEqual(key1, value1), newValues, skipEqualValues); return applyIf(BlackMisc::Predicates::MemberEqual(key1, value1), newValues, skipEqualValues);
} }
/*! //! Remove all elements equal to the given object, if it is contained.
* \brief Remove all elements equal to the given object, if it is contained. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized. //! \return The number of elements removed.
* \return The number of elements removed.
*/
int remove(const T &object) int remove(const T &object)
{ {
const auto newEnd = std::remove(begin(), end(), object); const auto newEnd = std::remove(begin(), end(), object);
@@ -390,11 +280,9 @@ namespace BlackMisc
return count; return count;
} }
/*! //! Remove elements for which a given predicate returns true.
* \brief Remove elements for which a given predicate returns true. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized. //! \return The number of elements removed.
* \return The number of elements removed.
*/
template <class Predicate> template <class Predicate>
int removeIf(Predicate p) int removeIf(Predicate p)
{ {
@@ -412,20 +300,16 @@ namespace BlackMisc
return CSequence::CContainerBase::removeIf(k0, v0, keysValues...); return CSequence::CContainerBase::removeIf(k0, v0, keysValues...);
} }
/*! //! Remove all elements if they are in other
* \brief Remove all elements if they are in other //! \pre The sequence must be initialized.
* \pre The sequence must be initialized. //! \return The number of elements removed.
* \return The number of elements removed.
*/
int removeIfIn(const CSequence &other) int removeIfIn(const CSequence &other)
{ {
return removeIf([&other](const T &v) { return other.contains(v); }); return removeIf([&other](const T &v) { return other.contains(v); });
} }
/*! //! Replace elements matching the given element with a replacement.
* \brief Replace elements matching the given element with a replacement. //! \return The number of elements replaced.
* \return The number of elements replaced.
*/
int replace(const T &original, const T &replacement) int replace(const T &original, const T &replacement)
{ {
int count = 0; int count = 0;
@@ -436,10 +320,8 @@ namespace BlackMisc
return count; return count;
} }
/*! //! Replace elements for which a given predicate returns true.
* \brief Replace elements for which a given predicate returns true. //! \return The number of elements replaced.
* \return The number of elements replaced.
*/
template <class Predicate> template <class Predicate>
int replaceIf(Predicate p, const T &replacement) int replaceIf(Predicate p, const T &replacement)
{ {
@@ -451,23 +333,19 @@ namespace BlackMisc
return count; return count;
} }
/*! //! Replace elements matching a particular key/value pair.
* \brief Replace elements matching a particular key/value pair. //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param value1 Will be compared to the return value of key1.
* \param value1 Will be compared to the return value of key1. //! \param replacement All matching elements will be replaced by copies of this one.
* \param replacement All matching elements will be replaced by copies of this one. //! \return The number of elements replaced.
* \return The number of elements replaced.
*/
template <class K1, class V1> template <class K1, class V1>
int replaceIf(K1 key1, V1 value1, const T &replacement) int replaceIf(K1 key1, V1 value1, const T &replacement)
{ {
return replaceIf(BlackMisc::Predicates::MemberEqual(key1, value1), replacement); return replaceIf(BlackMisc::Predicates::MemberEqual(key1, value1), replacement);
} }
/*! //! Replace elements for which a given predicate returns true. If there is no match, push the new element on the end.
* \brief Replace elements for which a given predicate returns true. If there is no match, push the new element on the end. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
template <class Predicate> template <class Predicate>
void replaceOrAdd(Predicate p, const T &replacement) void replaceOrAdd(Predicate p, const T &replacement)
{ {
@@ -475,23 +353,19 @@ namespace BlackMisc
else { push_back(replacement); } else { push_back(replacement); }
} }
/*! //! Replace elements matching the given element. If there is no match, push the new element on the end.
* \brief Replace elements matching the given element. If there is no match, push the new element on the end. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
void replaceOrAdd(const T &original, const T &replacement) void replaceOrAdd(const T &original, const T &replacement)
{ {
if (this->contains(original)) { replace(original, replacement); } if (this->contains(original)) { replace(original, replacement); }
else { push_back(replacement); } else { push_back(replacement); }
} }
/*! //! Replace elements matching a particular key/value pair. If there is no match, push the new element on the end.
* \brief Replace elements matching a particular key/value pair. If there is no match, push the new element on the end. //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param value1 Will be compared to the return value of key1.
* \param value1 Will be compared to the return value of key1. //! \param replacement All matching elements will be replaced by copies of this one, or a copy will be added.
* \param replacement All matching elements will be replaced by copies of this one, or a copy will be added. //! \pre The sequence must be initialized.
* \pre The sequence must be initialized.
*/
template <class K1, class V1> template <class K1, class V1>
void replaceOrAdd(K1 key1, V1 value1, const T &replacement) void replaceOrAdd(K1 key1, V1 value1, const T &replacement)
{ {
@@ -499,27 +373,21 @@ namespace BlackMisc
else { push_back(replacement); } else { push_back(replacement); }
} }
/*! //! In-place sort by a given comparator predicate.
* \brief In-place sort by a given comparator predicate.
*/
template <class Predicate> void sort(Predicate p) template <class Predicate> void sort(Predicate p)
{ {
std::sort(begin(), end(), p); std::sort(begin(), end(), p);
} }
/*! //! In-place sort by some particular key(s).
* \brief In-place sort by some particular key(s). //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param keys Zero or more additional pointers to member functions of T.
* \param keys Zero or more additional pointers to member functions of T.
*/
template <class K1, class... Keys> void sortBy(K1 key1, Keys... keys) template <class K1, class... Keys> void sortBy(K1 key1, Keys... keys)
{ {
sort(BlackMisc::Predicates::MemberLess(key1, keys...)); sort(BlackMisc::Predicates::MemberLess(key1, keys...));
} }
/*! //! Return a copy sorted by a given comparator predicate.
* \brief Return a copy sorted by a given comparator predicate.
*/
template <class Predicate> template <class Predicate>
CSequence sorted(Predicate p) const CSequence sorted(Predicate p) const
{ {
@@ -528,39 +396,31 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Return a copy sorted by some particular key(s).
* \brief Return a copy sorted by some particular key(s). //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param keys Zero or more additional pointers to member functions of T.
* \param keys Zero or more additional pointers to member functions of T.
*/
template <class K1, class... Keys> template <class K1, class... Keys>
CSequence sortedBy(K1 key1, Keys... keys) const CSequence sortedBy(K1 key1, Keys... keys) const
{ {
return sorted(BlackMisc::Predicates::MemberLess(key1, keys...)); return sorted(BlackMisc::Predicates::MemberLess(key1, keys...));
} }
/*! //! In-place move the smallest n elements to the beginning and sort them.
* \brief In-place move the smallest n elements to the beginning and sort them.
*/
template <class Predicate> void partiallySort(size_type n, Predicate p) template <class Predicate> void partiallySort(size_type n, Predicate p)
{ {
std::partial_sort(begin(), begin() + n, end(), p); std::partial_sort(begin(), begin() + n, end(), p);
} }
/*! //! In-place partially sort by some particular key(s).
* \brief In-place partially sort by some particular key(s). //! \param n size.
* \param n size. //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param keys Zero or more additional pointers to member functions of T.
* \param keys Zero or more additional pointers to member functions of T.
*/
template <class K1, class... Keys> void partiallySortBy(size_type n, K1 key1, Keys... keys) template <class K1, class... Keys> void partiallySortBy(size_type n, K1 key1, Keys... keys)
{ {
partiallySort(n, BlackMisc::Predicates::MemberLess(key1, keys...)); partiallySort(n, BlackMisc::Predicates::MemberLess(key1, keys...));
} }
/*! //! Return a copy with the smallest n elements at the beginning and sorted.
* \brief Return a copy with the smallest n elements at the beginning and sorted.
*/
template <class Predicate> template <class Predicate>
CSequence partiallySorted(size_type n, Predicate p) const CSequence partiallySorted(size_type n, Predicate p) const
{ {
@@ -569,21 +429,17 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Return a copy partially sorted by some particular key(s).
* \brief Return a copy partially sorted by some particular key(s). //! \param n size
* \param n size //! \param key1 A pointer to a member function of T.
* \param key1 A pointer to a member function of T. //! \param keys Zero or more additional pointers to member functions of T.
* \param keys Zero or more additional pointers to member functions of T.
*/
template <class K1, class... Keys> template <class K1, class... Keys>
CSequence partiallySortedBy(size_type n, K1 key1, Keys... keys) const CSequence partiallySortedBy(size_type n, K1 key1, Keys... keys) const
{ {
return partiallySorted(n, BlackMisc::Predicates::MemberLess(key1, keys...)); return partiallySorted(n, BlackMisc::Predicates::MemberLess(key1, keys...));
} }
/*! //! Split up the sequence into subsequences for which the given predicate returns the same value.
* Split up the sequence into subsequences for which the given predicate returns the same value.
*/
template <class Predicate> template <class Predicate>
auto separate(Predicate p) const -> QMap<decltype(p(std::declval<T>())), CSequence> auto separate(Predicate p) const -> QMap<decltype(p(std::declval<T>())), CSequence>
{ {
@@ -599,9 +455,7 @@ namespace BlackMisc
return result; return result;
} }
/*! //! Split up the sequence into subsequences of elements having the same value for the given key.
* Split up the sequence into subsequences of elements having the same value for the given key.
*/
template <class Key> template <class Key>
auto separateBy(Key k) const -> QMap<decltype(std::declval<T>().*k), CSequence> auto separateBy(Key k) const -> QMap<decltype(std::declval<T>().*k), CSequence>
{ {
@@ -633,11 +487,9 @@ namespace BlackMisc
//! Greater or equal operator. //! Greater or equal operator.
friend bool operator >=(const CSequence &a, const CSequence &b) { return !(a < b); } friend bool operator >=(const CSequence &a, const CSequence &b) { return !(a < b); }
/*! //! Return an opaque pointer to the implementation container.
* \brief Return an opaque pointer to the implementation container. //! \details Can be useful in unusual debugging situations.
* \details Can be useful in unusual debugging situations. //! \warning Not for general use.
* \warning Not for general use.
*/
void *getImpl() { return pimpl() ? pimpl()->impl() : nullptr; } void *getImpl() { return pimpl() ? pimpl()->impl() : nullptr; }
private: private: