//! \addtogroup Containers //! \{ //! \~\file piset.h //! \~\brief //! \~english Declares \a PISet //! \~russian Объявление \a PISet //! \~\} /* PIP - Platform Independent Primitives Set container Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PISET_H #define PISET_H #include "pimap.h" //! \addtogroup Containers //! \{ //! \class PISet //! \~\brief //! \~english Set of unique values. //! \~russian Множество уникальных значений. //! \~\} //! \~\details //! \~english //! This class is used to store a collection of unique elements of any type. //! You can add values to the set using \a operator<< or the \a insert() function. //! You can check if a value already exists in the set using \a operator[] or the \a contains() function. //! These operations have logarithmic complexity. //! To iterate over all elements, use STL-style iterators \a begin() and \a end(). //! //! The set is implemented as a wrapper around \a PIMap, where keys are the elements //! and values are dummy byte values (used only for storage). //! \~russian //! Этот класс используется для хранения коллекции уникальных элементов любого типа. //! Вы можете добавлять значения в множество с помощью \a operator<< или функции \a insert(). //! Вы можете проверить, существует ли значение в множестве, используя \a operator[] или функцию \a contains(). //! Эти операции имеют логарифмическую сложность. //! Для перебора всех элементов используйте итераторы в стиле STL \a begin() и \a end(). //! //! Множество реализовано как обёртка над \a PIMap, где ключами являются элементы, //! а значениями являются фиктивные байтовые значения (используются только для хранения). //! \~\sa \a PIMap, \a PIVector template class PISet: public PIMap { typedef PIMap _CSet; template friend PIBinaryStream

& operator<<(PIBinaryStream

& s, const PISet & v); template friend PIBinaryStream

& operator>>(PIBinaryStream

& s, PISet & v); public: //! \~english Constructs an empty set. //! \~russian Создает пустое множество. PISet() {} //! \~english Constructs a set containing `value`. //! \~russian Создает множество, содержащее `value`. explicit PISet(const T & value) { _CSet::insert(value, 0); } //! \~english Constructs a set containing `v0` and `v1`. //! \~russian Создает множество, содержащее `v0` и `v1`. PISet(const T & v0, const T & v1) { _CSet::insert(v0, 0); _CSet::insert(v1, 0); } //! \~english Constructs a set containing `v0`, `v1` and `v2`. //! \~russian Создает множество, содержащее `v0`, `v1` и `v2`. PISet(const T & v0, const T & v1, const T & v2) { _CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0); } //! \~english Constructs a set containing `v0`, `v1`, `v2` and `v3`. //! \~russian Создает множество, содержащее `v0`, `v1`, `v2` и `v3`. PISet(const T & v0, const T & v1, const T & v2, const T & v3) { _CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0); _CSet::insert(v3, 0); } //! \~\brief //! \~english Constant iterator over \a PISet elements. //! \~russian Константный итератор по элементам \a PISet. class const_iterator { friend class PISet; private: inline const_iterator(const PISet * v, ssize_t p): parent(v), pos(p) {} const PISet * parent; ssize_t pos; public: typedef T value_type; typedef T * pointer; typedef T & reference; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; //! \~english Constructs an invalid iterator. //! \~russian Создает недействительный итератор. inline const_iterator(): parent(0), pos(0) {} //! \~english Returns the current element. //! \~russian Возвращает текущий элемент. inline const T & operator*() const { return parent->pim_index[pos].key; } //! \~english Provides access to the current element. //! \~russian Предоставляет доступ к текущему элементу. inline const T & operator->() const { return parent->pim_index[pos].key; } //! \~english Moves iterator to the next element. //! \~russian Перемещает итератор к следующему элементу. inline const_iterator & operator++() { ++pos; return *this; } //! \~english Returns iterator before incrementing. //! \~russian Возвращает итератор до увеличения. inline const_iterator operator++(int) { const auto tmp = *this; ++*this; return tmp; } //! \~english Moves iterator to the previous element. //! \~russian Перемещает итератор к предыдущему элементу. inline const_iterator & operator--() { --pos; return *this; } //! \~english Returns iterator before decrementing. //! \~russian Возвращает итератор до уменьшения. inline const_iterator operator--(int) { const auto tmp = *this; --*this; return tmp; } //! \~english Adds offset of iterator `it`. //! \~russian Добавляет смещение итератора `it`. inline const_iterator & operator+=(const const_iterator & it) { pos += it.pos; return *this; } //! \~english Advances iterator by `p` elements. //! \~russian Сдвигает итератор вперед на `p` элементов. inline const_iterator & operator+=(size_t p) { pos += p; return *this; } //! \~english Subtracts offset of iterator `it`. //! \~russian Вычитает смещение итератора `it`. inline const_iterator & operator-=(const const_iterator & it) { pos -= it.pos; return *this; } //! \~english Moves iterator back by `p` elements. //! \~russian Сдвигает итератор назад на `p` элементов. inline const_iterator & operator-=(size_t p) { pos -= p; return *this; } //! \~english Returns iterator shifted back by `p`. //! \~russian Возвращает итератор, сдвинутый назад на `p`. friend inline const_iterator operator-(size_t p, const const_iterator & it) { return it - p; } //! \~english Returns iterator shifted back by `p`. //! \~russian Возвращает итератор, сдвинутый назад на `p`. friend inline const_iterator operator-(const const_iterator & it, size_t p) { auto tmp = it; tmp -= p; return tmp; } //! \~english Returns distance between iterators. //! \~russian Возвращает расстояние между итераторами. friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; } //! \~english Returns iterator shifted forward by `p`. //! \~russian Возвращает итератор, сдвинутый вперед на `p`. friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; } //! \~english Returns iterator shifted forward by `p`. //! \~russian Возвращает итератор, сдвинутый вперед на `p`. friend inline const_iterator operator+(const const_iterator & it, size_t p) { auto tmp = it; tmp += p; return tmp; } //! \~english Checks iterator equality. //! \~russian Проверяет равенство итераторов. inline bool operator==(const const_iterator & it) const { return (pos == it.pos); } //! \~english Checks iterator inequality. //! \~russian Проверяет неравенство итераторов. inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); } //! \~english Checks whether `it1` is before `it2`. //! \~russian Проверяет, находится ли `it1` перед `it2`. friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; } //! \~english Checks whether `it1` is before or equal to `it2`. //! \~russian Проверяет, находится ли `it1` перед `it2` или совпадает с ним. friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; } //! \~english Checks whether `it1` is after `it2`. //! \~russian Проверяет, находится ли `it1` после `it2`. friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; } //! \~english Checks whether `it1` is after or equal to `it2`. //! \~russian Проверяет, находится ли `it1` после `it2` или совпадает с ним. friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; } }; //! \~english Returns iterator to the first element. //! \~russian Возвращает итератор на первый элемент. inline const_iterator begin() const { return const_iterator(this, 0); } //! \~english Returns iterator following the last element. //! \~russian Возвращает итератор на элемент, следующий за последним. inline const_iterator end() const { return const_iterator(this, _CSet::size()); } //! \~english Constructs a set from vector `values`. //! \~russian Создает множество из вектора `values`. explicit PISet(const PIVector & values) { if (values.isEmpty()) return; for (int i = 0; i < values.size_s(); ++i) { _CSet::insert(values[i], 0); } } //! \~english Constructs a set from deque `values`. //! \~russian Создает множество из дека `values`. explicit PISet(const PIDeque & values) { if (values.isEmpty()) return; for (int i = 0; i < values.size_s(); ++i) { _CSet::insert(values[i], 0); } } typedef T key_type; //! \~english Inserts `t` into the set. //! \~russian Добавляет `t` в множество. PISet & operator<<(const T & t) { _CSet::insert(t, 0); return *this; } //! \~english Moves `t` into the set. //! \~russian Перемещает `t` в множество. PISet & operator<<(T && t) { _CSet::insert(std::move(t), 0); return *this; } //! \~english Inserts all elements from `other`. //! \~russian Добавляет все элементы из `other`. PISet & operator<<(const PISet & other) { (*(_CSet *)this) << *((_CSet *)&other); return *this; } //! \~english Tests whether element `t` exists in the set. //! \~russian Проверяет наличие элемента `t` в множестве. inline bool contains(const T & t) const { return _CSet::contains(t); } //! \~english Checks whether element `t` exists in the set. //! \~russian Проверяет наличие элемента `t` в множестве. bool operator[](const T & t) const { return _CSet::contains(t); } //! \~english Removes element `t` from the set. //! \~russian Удаляет элемент `t` из множества. PISet & remove(const T & t) { _CSet::remove(t); return *this; } //! \~english Unites the set with `v`. //! \~russian Объединяет множество с `v`. PISet & unite(const PISet & v) { for (const auto & i: v) _CSet::insert(i, 0); return *this; } //! \~english Removes all elements present in `v`. //! \~russian Удаляет все элементы, присутствующие в `v`. PISet & subtract(const PISet & v) { for (const auto & i: v) _CSet::remove(i); return *this; } //! \~english Leaves only elements also present in `v`. //! \~russian Оставляет только элементы, которые есть и в `v`. PISet & intersect(const PISet & v) { _CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); }); return *this; } //! \~english Same as \a unite(). //! \~russian Синоним \a unite(). PISet & operator+=(const PISet & v) { return unite(v); } //! \~english Same as \a unite(). //! \~russian Синоним \a unite(). PISet & operator|=(const PISet & v) { return unite(v); } //! \~english Same as \a subtract(). //! \~russian Синоним \a subtract(). PISet & operator-=(const PISet & v) { return subtract(v); } //! \~english Same as \a intersect(). //! \~russian Синоним \a intersect(). PISet & operator&=(const PISet & v) { return intersect(v); } //! \~english Returns set contents as \a PIVector. //! \~russian Возвращает содержимое множества в виде \a PIVector. PIVector toVector() const { PIVector ret; for (const auto & i: *this) ret << i; return ret; } //! \~english Returns set contents as \a PIDeque. //! \~russian Возвращает содержимое множества в виде \a PIDeque. PIDeque toDeque() const { PIDeque ret; for (const auto & i: *this) ret << i; return ret; } }; //! \relatesalso PISet //! \~english Returns union of two sets. //! \~russian Возвращает объединение двух множеств. template PISet operator+(const PISet & v0, const PISet & v1) { PISet ret(v0); ret.unite(v1); return ret; } //! \relatesalso PISet //! \~english Returns difference of two sets. //! \~russian Возвращает разность двух множеств. template PISet operator-(const PISet & v0, const PISet & v1) { PISet ret(v0); ret.subtract(v1); return ret; } //! \relatesalso PISet //! \~english Returns union of two sets. //! \~russian Возвращает объединение двух множеств. template PISet operator|(const PISet & v0, const PISet & v1) { PISet ret(v0); ret.unite(v1); return ret; } //! \relatesalso PISet //! \~english Returns intersection of two sets. //! \~russian Возвращает пересечение двух множеств. template PISet operator&(const PISet & v0, const PISet & v1) { PISet ret(v0); ret.intersect(v1); return ret; } //! \relatesalso PISet //! \~english Output operator to \a PICout. //! \~russian Оператор вывода в \a PICout. template inline PICout operator<<(PICout s, const PISet & v) { s.space(); s.saveAndSetControls(0); s << "{"; bool first = true; for (const auto & i: v) { if (!first) s << ", "; first = false; s << i; } s << "}"; s.restoreControls(); return s; } #endif // PISET_H