359 lines
12 KiB
C++
359 lines
12 KiB
C++
//! \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
|