Files
pip/libs/main/containers/piset.h
2026-03-12 14:46:57 +03:00

427 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \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 <http://www.gnu.org/licenses/>.
*/
#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<typename T>
class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet;
template<typename P, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<T1> & v);
template<typename P, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & 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<T>;
private:
inline const_iterator(const PISet<T> * v, ssize_t p): parent(v), pos(p) {}
const PISet<T> * 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<T> & 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<T> & 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<T> & operator<<(const T & t) {
_CSet::insert(t, 0);
return *this;
}
//! \~english Moves `t` into the set.
//! \~russian Перемещает `t` в множество.
PISet<T> & operator<<(T && t) {
_CSet::insert(std::move(t), 0);
return *this;
}
//! \~english Inserts all elements from `other`.
//! \~russian Добавляет все элементы из `other`.
PISet<T> & operator<<(const PISet<T> & 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<T> & remove(const T & t) {
_CSet::remove(t);
return *this;
}
//! \~english Unites the set with `v`.
//! \~russian Объединяет множество с `v`.
PISet<T> & unite(const PISet<T> & v) {
for (const auto & i: v)
_CSet::insert(i, 0);
return *this;
}
//! \~english Removes all elements present in `v`.
//! \~russian Удаляет все элементы, присутствующие в `v`.
PISet<T> & subtract(const PISet<T> & v) {
for (const auto & i: v)
_CSet::remove(i);
return *this;
}
//! \~english Leaves only elements also present in `v`.
//! \~russian Оставляет только элементы, которые есть и в `v`.
PISet<T> & intersect(const PISet<T> & v) {
_CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
return *this;
}
//! \~english Same as \a unite().
//! \~russian Синоним \a unite().
PISet<T> & operator+=(const PISet<T> & v) { return unite(v); }
//! \~english Same as \a unite().
//! \~russian Синоним \a unite().
PISet<T> & operator|=(const PISet<T> & v) { return unite(v); }
//! \~english Same as \a subtract().
//! \~russian Синоним \a subtract().
PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); }
//! \~english Same as \a intersect().
//! \~russian Синоним \a intersect().
PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); }
//! \~english Returns set contents as \a PIVector.
//! \~russian Возвращает содержимое множества в виде \a PIVector.
PIVector<T> toVector() const {
PIVector<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
//! \~english Returns set contents as \a PIDeque.
//! \~russian Возвращает содержимое множества в виде \a PIDeque.
PIDeque<T> toDeque() const {
PIDeque<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
};
//! \relatesalso PISet
//! \~english Returns union of two sets.
//! \~russian Возвращает объединение двух множеств.
template<typename T>
PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet
//! \~english Returns difference of two sets.
//! \~russian Возвращает разность двух множеств.
template<typename T>
PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.subtract(v1);
return ret;
}
//! \relatesalso PISet
//! \~english Returns union of two sets.
//! \~russian Возвращает объединение двух множеств.
template<typename T>
PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet
//! \~english Returns intersection of two sets.
//! \~russian Возвращает пересечение двух множеств.
template<typename T>
PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.intersect(v1);
return ret;
}
//! \relatesalso PISet
//! \~english Output operator to \a PICout.
//! \~russian Оператор вывода в \a PICout.
template<typename Type>
inline PICout operator<<(PICout s, const PISet<Type> & 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