Files
pip/libs/main/containers/pimap.h
2026-03-07 17:00:45 +03:00

991 lines
36 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 pimap.h
//! \~\brief
//! \~english Declares \a PIMap
//! \~russian Объявление \a PIMap
//! \~\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
Associative array with custom types of key and value
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 PIMAP_H
#define PIMAP_H
#include "pideque.h"
#include "pipair.h"
#include "pivector.h"
template<typename Key, typename T>
class PIMapIteratorConst;
template<typename Key, typename T>
class PIMapIteratorConstReverse;
template<typename Key, typename T>
class PIMapIterator;
template<typename Key, typename T>
class PIMapIteratorReverse;
//! \addtogroup Containers
//! \{
//! \class PIMap
//! \~\brief
//! \~english Map of unique keys and associated values.
//! \~russian Словарь с уникальными ключами и связанными значениями.
//! \~\}
//! \~\details
//! \~english
//! Stores key/value pairs and keeps keys unique.
//! \a value() returns the value for a key or the provided default,
//! while \a operator[] creates a default value for a missing key.
//! Use \a keys() and \a values() to retrieve map contents,
//! and \a makeIterator() or \a makeReverseIterator() to traverse entries.
//! \~russian
//! Хранит пары ключ/значение и поддерживает уникальность ключей.
//! \a value() возвращает значение по ключу или значение по умолчанию,
//! а \a operator[] создает значение по умолчанию для отсутствующего ключа.
//! Для получения содержимого используйте \a keys() и \a values(),
//! а для обхода элементов - \a makeIterator() или \a makeReverseIterator().
template<typename Key, typename T>
class PIMap {
template<typename Key1, typename T1>
friend class PIMapIteratorConst;
template<typename Key1, typename T1>
friend class PIMapIteratorConstReverse;
template<typename Key1, typename T1>
friend class PIMapIterator;
template<typename Key1, typename T1>
friend class PIMapIteratorReverse;
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
public:
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
//! \~english Constructs an empty map.
//! \~russian Создает пустой словарь.
inline PIMap() {}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIMap(const PIMap<Key, T> & other): pim_content(other.pim_content), pim_index(other.pim_index) {}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIMap(PIMap<Key, T> && other): pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
//! \~english Contructs map from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает словарь из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
//! piCout << m; // {1: a, 2: b}
//! \endcode
inline PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list) {
insert(std::get<0>(i), std::get<1>(i));
}
}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIMap<Key, T> & operator=(const PIMap<Key, T> & other) {
if (this == &other) return *this;
clear();
pim_content = other.pim_content;
pim_index = other.pim_index;
return *this;
}
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIMap<Key, T> & operator=(PIMap<Key, T> && other) {
swap(other);
return *this;
}
class iterator {
friend class PIMap<Key, T>;
private:
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const iterator & it) const { return (pos == it.pos); }
bool operator!=(const iterator & it) const { return (pos != it.pos); }
};
class reverse_iterator {
friend class PIMap<Key, T>;
private:
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
reverse_iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
};
class const_iterator {
friend class PIMap<Key, T>;
private:
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
const T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const const_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
};
class const_reverse_iterator {
friend class PIMap<Key, T>;
private:
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_reverse_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
};
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
inline iterator begin() { return iterator(this, 0); }
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
inline iterator end() { return iterator(this, size()); }
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, size()); }
//! \~english Returns a reverse iterator to the last map entry.
//! \~russian Обратный итератор на первый элемент.
inline reverse_iterator rbegin() { return reverse_iterator(this, size() - 1); }
//! \~english Returns a reverse iterator to the position before the first map entry.
//! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, size() - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
//! \relatesalso PIMapIteratorConst
inline PIMapIteratorConst<Key, T> makeIterator() const { return PIMapIteratorConst<Key, T>(*this); }
//! \relatesalso PIMapIterator
inline PIMapIterator<Key, T> makeIterator() { return PIMapIterator<Key, T>(*this); }
//! \relatesalso PIMapIteratorConstReverse
inline PIMapIteratorConstReverse<Key, T> makeReverseIterator() const { return PIMapIteratorConstReverse<Key, T>(*this); }
//! \relatesalso PIMapIteratorReverse
inline PIMapIteratorReverse<Key, T> makeReverseIterator() { return PIMapIteratorReverse<Key, T>(*this); }
//! \~english Number of entries in the map.
//! \~russian Количество элементов в словаре.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return pim_content.size(); }
//! \~english Number of entries in the map as a signed value.
//! \~russian Количество элементов в словаре в виде знакового числа.
//! \~\sa \a size(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline int size_s() const { return pim_content.size_s(); }
//! \~english Same as \a size().
//! \~russian Синоним \a size().
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t length() const { return pim_content.size(); }
//! \~english Checks whether the map is empty.
//! \~russian Проверяет, пуст ли словарь.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isEmpty() const { return (pim_content.size() == 0); }
//! \~english Checks whether the map contains entries.
//! \~russian Проверяет, содержит ли словарь элементы.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (pim_content.size() > 0); }
//! \~english Full access to element key `key`.
//! \~russian Полный доступ к элементу по ключу `key`.
//! \~\details
//! \~english If the map contains no item with key `key`,
//! the function inserts a default-constructed value into the map with key `key`,
//! and returns a reference to it.
//! \~russian Если элемента с таким ключом `key` не существует,
//! то он будет создан конструктором по умолчанию и добавлен в словарь
//! по ключу `key`, а затем возвращена ссылка на этот новый элемент.
//! \~\code
//! PIMap <PIString, int> m;
//! m["огурец"] = 500;
//! piCout << m; // {огурец: 500}
//! m["лук"] = 25;
//! piCout << m; // {огурец: 500, лук: 25}
//! m["огурец"] = 350;
//! piCout << m; // {огурец: 350, лук: 25}
//! \endcode
//! \~\sa \a insert(), \a value(), \a key()
inline T & operator[](const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) return _value(i);
pim_content.push_back(T());
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
return pim_content.back();
}
//! \~english Read only access to element by `key`.
//! \~russian Доступ исключительно на чтение к элементу по ключу `key`.
//! \~\note
//! \~english Element with key `key` must exists,
//! otherwise it will lead to undefined program behavior and memory errors.
//! \~russian Элемент по ключу `key` должен существовать,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\sa \a operator[](), \a value(), \a key()
inline const T & at(const Key & key) const {
bool f(false);
const ssize_t i = _find(key, f);
return _value(i);
}
//! \~english Removes entry with key `key` and returns its value.
//! \~russian Удаляет элемент с ключом `key` и возвращает его значение.
inline T take(const Key & key, const T & default_ = T()) {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_;
const T ret = _value(i);
_remove(i);
return ret;
}
//! \~english Inserts all entries from `other`, overwriting existing keys.
//! \~russian Добавляет все элементы из `other`, перезаписывая существующие ключи.
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
#ifndef NDEBUG
if (&other == this) {
fprintf(stderr, "error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
if (other.isEmpty()) return *this;
if (other.size() == 1) {
insert(other.pim_index[0].key, other.pim_content[0]);
return *this;
}
if (other.size() == 2) {
insert(other.pim_index[0].key, other.pim_content[other.pim_index[0].index]);
insert(other.pim_index[1].key, other.pim_content[other.pim_index[1].index]);
return *this;
}
for (int i = 0; i < other.pim_index.size_s(); ++i) {
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
}
return *this;
}
//! \~english Compares this map with `m`.
//! \~russian Сравнивает этот словарь с `m`.
inline bool operator==(const PIMap<Key, T> & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); }
//! \~english Compares this map with `m`.
//! \~russian Сравнивает этот словарь с `m`.
inline bool operator!=(const PIMap<Key, T> & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); }
//! \~english Checks whether the map contains key `key`.
//! \~russian Проверяет, содержит ли словарь ключ `key`.
inline bool contains(const Key & key) const {
bool f(false);
_find(key, f);
return f;
}
//! \~english Checks whether the map contains value `value`.
//! \~russian Проверяет, содержит ли словарь значение `value`.
inline bool containsValue(const T & value) const { return pim_content.contains(value); }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
inline PIMap<Key, T> & reserve(size_t new_size) {
pim_content.reserve(new_size);
pim_index.reserve(new_size);
return *this;
}
//! \~english Removes entry with key `key`.
//! \~russian Удаляет элемент с ключом `key`.
inline PIMap<Key, T> & remove(const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) _remove(i);
return *this;
}
//! \~english Removes all entries
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
inline PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
if (test(mi.key, pim_content[mi.index])) {
_remove(i);
--i;
}
}
return *this;
}
//! \~english Same as \a remove().
//! \~russian Синоним функции \a remove().
inline PIMap<Key, T> & erase(const Key & key) { return remove(key); }
//! \~english Clears the map.
//! \~russian Очищает словарь.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
inline PIMap<Key, T> & clear() {
pim_content.clear();
pim_index.clear();
return *this;
}
//! \~english Swaps this map with `other`.
//! \~russian Меняет местами этот словарь и `other`.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIMap<Key, T> & other) {
pim_content.swap(other.pim_content);
pim_index.swap(other.pim_index);
}
//! \~english Inserts value `value` for key `key`.
//! \~russian Вставляет значение `value` по ключу `key`.
//! \~\details
//! \~english If an element with the key `key` already exists, it will be overwritten with the value `value`.
//! \~russian Если элемент с ключом `key` уже существует, то он будет перезаписан на значение `value`.
inline PIMap<Key, T> & insert(const Key & key, const T & value) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) {
_value(i) = value;
} else {
pim_content.push_back(value);
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
}
return *this;
}
inline PIMap<Key, T> & insert(const Key & key, T && value) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) {
_value(i) = std::move(value);
} else {
pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
}
return *this;
}
//! \~english Inserts entry `pair`.
//! \~russian Вставляет элемент `pair`.
//! \~\details
//! \~english The first element of the pair is the key, and the second is the value.
//! \~russian Первый элемент пары является ключом, а второй значением.
inline PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
bool f(false);
const ssize_t i = _find(pair.first, f);
if (f) {
_value(i) = pair.second;
} else {
pim_content.push_back(pair.second);
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
}
return *this;
}
inline PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
bool f(false);
Key k(std::move(pair.first));
const ssize_t i = _find(k, f);
if (f) {
_value(i) = std::move(pair.second);
} else {
pim_content.push_back(std::move(pair.second));
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
}
return *this;
}
//! \~english Returns the value of the element by the key `key`
//! or `default_` if there is no such element.
//! \~russian Возвращает значение элемента по ключу `key`
//! или `default_` если такого элемента нет.
inline T value(const Key & key, const T & default_ = T()) const {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_;
return _value(i);
}
//! \~english Returns values of all map entries.
//! \~russian Возвращает значения всех элементов словаря.
inline PIVector<T> values() const { return pim_content; }
//! \~english Returns the key of the first element
//! whose value matches `value` or `default_` if there is no such element.
//! \~russian Возвращает ключ первого элемента, значение которого
//! совпадает с `value` или `default_` если такого элемента нет.
inline Key key(const T & value, const Key & default_ = Key()) const {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
if (pim_content[mi.index] == value) {
return mi.key;
}
}
return default_;
}
//! \~english Returns keys of all map entries.
//! \~russian Возвращает ключи всех элементов словаря.
inline PIVector<Key> keys() const {
PIVector<Key> ret;
ret.reserve(pim_index.size());
for (int i = 0; i < pim_index.size_s(); ++i) {
ret << pim_index[i].key;
}
return ret;
}
//! \~english Calls `f` for every map entry.
//! \~russian Вызывает `f` для каждого элемента словаря.
inline void forEach(std::function<void(const Key & key, const T & value)> f) const {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
f(mi.key, pim_content[mi.index]);
}
}
//! \~english Creates a new \a PIMap from results of applying `f` to each map entry.
//! \~russian Создает новый \a PIMap из результатов применения `f` к каждому элементу словаря.
template<typename Key2, typename T2>
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const {
PIMap<Key2, T2> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret.insert(f(mi.key, pim_content[mi.index]));
}
return ret;
}
//! \~english Creates a new \a PIVector from results of applying `f` to each map entry.
//! \~russian Создает новый \a PIVector из результатов применения `f` к каждому элементу словаря.
template<typename ST>
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
PIVector<ST> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret << f(mi.key, pim_content[mi.index]);
}
return ret;
}
//! \~english Returns a new map with all entries
//! that pass the test implemented by the provided function `bool test(const Key & key, const T & value)`.
//! \~russian Возвращает новый словарь со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const Key & key, const T & value)`.
inline PIMap<Key, T> filter(std::function<bool(const Key & key, const T & value)> test) const {
PIMap<Key, T> ret;
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
const auto & v(pim_content[mi.index]);
if (test(mi.key, v)) {
ret.insert(mi.key, v);
}
}
return ret;
}
protected:
struct MapIndex {
MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {}
MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {}
Key key;
size_t index;
bool operator==(const MapIndex & s) const { return key == s.key; }
bool operator!=(const MapIndex & s) const { return key != s.key; }
bool operator<(const MapIndex & s) const { return key < s.key; }
bool operator>(const MapIndex & s) const { return key > s.key; }
};
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
PIVector<T> pim_content;
PIDeque<MapIndex> pim_index;
private:
inline ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid = 0;
while (first <= last) {
mid = (first + last) / 2;
if (key > pim_index[mid].key)
first = mid + 1;
else if (key < pim_index[mid].key)
last = mid - 1;
else {
found = true;
return mid;
}
}
found = false;
return first;
}
inline ssize_t _find(const Key & k, bool & found) const {
if (pim_index.isEmpty()) {
found = false;
return 0;
}
return _binarySearch(0, pim_index.size_s() - 1, k, found);
}
inline void _remove(ssize_t index) {
const size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
pim_index.remove(index);
for (size_t i = 0; i < pim_index.size(); ++i) {
if (pim_index[i].index == bi) {
pim_index[i].index = ci;
break;
}
}
piSwap<T>(pim_content[ci], pim_content.back());
pim_content.resize(pim_index.size());
}
inline const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s()) return value_type();
const auto & mi(pim_index[index]);
return value_type(mi.key, pim_content[mi.index]);
}
inline Key & _key(ssize_t index) { return pim_index[index].key; }
inline const Key & _key(ssize_t index) const { return pim_index[index].key; }
inline T & _value(ssize_t index) { return pim_content[pim_index[index].index]; }
inline const T & _value(ssize_t index) const { return pim_content[pim_index[index].index]; }
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConst
//! \~\brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! Provides sequential read-only access to keys and values in \a PIMap.
//! Use the constructor directly or call \a PIMap::makeIterator().
//! \~russian
//! Используется для последовательного перебора ключей и значений \a PIMap только для чтения.
//! Можно использовать конструктор или вызвать \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 1 one
//! // 2 two
//! // 4 four
//! \endcode
template<typename Key, typename T>
class PIMapIteratorConst {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
const MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConstReverse
//! \~\brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! Provides sequential reverse read-only access to keys and values in \a PIMap.
//! Use the constructor directly or call \a PIMap::makeReverseIterator().
//! \~russian
//! Используется для последовательного обратного перебора ключей и значений \a PIMap только для чтения.
//! Можно использовать конструктор или вызвать \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 4 four
//! // 2 two
//! // 1 one
//! \endcode
template<typename Key, typename T>
class PIMapIteratorConstReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
const MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIterator
//! \~\brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! Provides sequential access to keys and values in \a PIMap with write access to values.
//! Use the constructor directly or call \a PIMap::makeIterator().
//! \~russian
//! Используется для последовательного перебора ключей и значений \a PIMap с доступом на запись.
//! Можно использовать конструктор или вызвать \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 1 one_!
//! // 2 two_!
//! // 4 four_!
//! \endcode
template<typename Key, typename T>
class PIMapIterator {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorReverse
//! \~\brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! Provides sequential reverse access to keys and values in \a PIMap with write access to values.
//! Use the constructor directly or call \a PIMap::makeReverseIterator().
//! \~russian
//! Используется для последовательного обратного перебора ключей и значений \a PIMap с доступом на запись.
//! Можно использовать конструктор или вызвать \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 4 four_!
//! // 2 two_!
//! // 1 one_!
//! \endcode
template<typename Key, typename T>
class PIMapIteratorReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
MapType & m;
ssize_t pos;
};
#ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename Key, typename Type>
inline std::ostream & operator<<(std::ostream & s, const PIMap<Key, Type> & v) {
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", ";
first = false;
s << i.key() << ": " << i.value();
}
s << "}";
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Key, typename Type>
inline PICout operator<<(PICout s, const PIMap<Key, Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", ";
first = false;
s << i.key() << ": " << i.value();
}
s << "}";
s.restoreControls();
return s;
}
template<typename Key, typename Type>
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {
f.swap(s);
}
#endif // PIMAP_H