416 lines
15 KiB
C++
416 lines
15 KiB
C++
//! \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
|
||
//! Stores unique values of type `T` and exposes the set interface on top of \a PIMap.
|
||
//! Values can be inserted with \a operator<<(), checked with \a contains() or \a operator[](),
|
||
//! and combined with \a unite(), \a subtract() and \a intersect().
|
||
//! \~russian
|
||
//! Хранит уникальные значения типа `T` и реализует интерфейс множества поверх \a PIMap.
|
||
//! Значения можно добавлять через \a operator<<(), проверять через \a contains() или \a operator[](),
|
||
//! а множества комбинировать через \a unite(), \a subtract() и \a intersect().
|
||
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
|