Files
pip/libs/main/containers/piset.h

359 lines
12 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
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/*
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 A set is a collection of unique elements.
//! \~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 with one element `value`.
//! \~russian Создает множество с одним элементом `value`.
explicit PISet(const T & value) { _CSet::insert(value, 0); }
//! \~english Constructs a set with two elements `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 with three elements `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 with four elements `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);
}
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;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return parent->pim_index[pos].key; }
inline const T & operator->() const { return parent->pim_index[pos].key; }
inline const_iterator & operator++() {
++pos;
return *this;
}
inline const_iterator operator++(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator--() {
--pos;
return *this;
}
inline const_iterator operator--(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline const_iterator & operator+=(const const_iterator & it) {
pos += it.pos;
return *this;
}
inline const_iterator & operator+=(size_t p) {
pos += p;
return *this;
}
inline const_iterator & operator-=(const const_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_iterator & operator-=(size_t p) {
pos -= p;
return *this;
}
friend inline const_iterator operator-(size_t p, const const_iterator & it) { return it - p; }
friend inline const_iterator operator-(const const_iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; }
friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; }
friend inline const_iterator operator+(const const_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
};
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, _CSet::size()); }
//! \~english Constructs a set from a vector of elements.
//! \~russian Создает множество из вектора элементов.
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 a deque of elements.
//! \~russian Создает множество из deque элементов.
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 element `t` into the set.
//! \~russian Вставляет элемент `t` в множество.
PISet<T> & operator<<(const T & t) {
_CSet::insert(t, 0);
return *this;
}
PISet<T> & operator<<(T && t) {
_CSet::insert(std::move(t), 0);
return *this;
}
PISet<T> & operator<<(const PISet<T> & other) {
(*(_CSet *)this) << *((_CSet *)&other);
return *this;
}
//! \~english Tests if element `t` exists in the set.
//! \~russian Проверяет наличие элемента `t` в множестве.
inline bool contains(const T & t) const { return _CSet::contains(t); }
//! \~english Tests if 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 Returns the union of this set with set `v`.
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & unite(const PISet<T> & v) {
for (const auto & i: v)
_CSet::insert(i, 0);
return *this;
}
//! \~english Returns the difference of this set and set `v`.
//! \~russian Возвращает разность этого множества и множества `v`.
PISet<T> & subtract(const PISet<T> & v) {
for (const auto & i: v)
_CSet::remove(i);
return *this;
}
//! \~english Returns the intersection of this set with set `v`.
//! \~russian Возвращает пересечение этого множества с множеством `v`.
PISet<T> & intersect(const PISet<T> & v) {
_CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
return *this;
}
//! \~english Returns the union of this set with set `v`.
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & operator+=(const PISet<T> & v) { return unite(v); }
//! \~english Returns the union of this set with set `v`.
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & operator|=(const PISet<T> & v) { return unite(v); }
//! \~english Returns the difference of this set and set `v`.
//! \~russian Возвращает разность этого множества и множества `v`.
PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); }
//! \~english Returns the intersection of this set with set `v`.
//! \~russian Возвращает пересечение этого множества с множеством `v`.
PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); }
//! \~english Converts the set to a vector.
//! \~russian Преобразует множество в вектор.
PIVector<T> toVector() const {
PIVector<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
//! \~english Converts the set to a deque.
//! \~russian Преобразует множество в deque.
PIDeque<T> toDeque() const {
PIDeque<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
};
//! \~english Returns the 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;
}
//! \~english Returns the 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;
}
//! \~english Returns the 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;
}
//! \~english Returns the 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 PICout
//! \~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