//! \addtogroup Containers //! \{ //! \file pideque.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 . */ #ifndef PIMAP_H #define PIMAP_H #include "pivector.h" #include "pideque.h" #include "pipair.h" template class PIMapIteratorConst; template class PIMapIteratorConstReverse; template class PIMapIterator; template class PIMapIteratorReverse; //! \addtogroup Containers //! \{ //! \class PIMap //! \brief //! \~english Associative array. //! \~russian Словарь. //! \~\} //! \details //! \~english //! A collection of key/value pairs, from which you retrieve a value using its associated key. //! There is a finite number of keys in the map, and each key has exactly one value associated with it. //! \a value() returns value for key and leave map //! unchaged in any case. \a operator [] create entry in map if //! there is no entry for given key. You can retrieve all //! keys by method \a keys() and all values by methos \a values(). //! To iterate all entries use class PIMapIterator, or methods //! \a makeIterator() and \a makeReverseIterator(). //! A key in the Map may only occur once. //! \~russian //! Словари, в принципе, похожи на обычные, используемые в повседневной жизни. //! Они хранят элементы одного и того же типа, индексируемые ключевыми значениями. //! Достоинство словаря в том, что он позволяет быстро получать значение, //! ассоциированное с заданным ключом. //! Ключи должны быть уникальными. //! Элемент //! В контейнеры этого типа заносятся элементы вместе с ключами, //! по которым их можно найти, которыми могут выступать значения любого типа. //! \a operator [] позволяет получить доступ к элементу по ключу, //! и если такого эелемента не было, то он будет создан. template class PIMap { template friend class PIMapIteratorConst; template friend class PIMapIteratorConstReverse; template friend class PIMapIterator; template friend class PIMapIteratorReverse; template friend PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIMap & v); template friend PIBinaryStream

& operator >>(PIBinaryStream

& s, PIMap & v); public: typedef T mapped_type; typedef Key key_type; typedef PIPair value_type; //! \~english Constructs an empty map. //! \~russian Создает пустой словарь. inline PIMap() {} //! \~english Copy constructor. //! \~russian Копирующий конструктор. inline PIMap(const PIMap & other) : pim_content(other.pim_content), pim_index(other.pim_index) {} //! \~english Move constructor. //! \~russian Перемещающий конструктор. inline PIMap(PIMap && 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 m{{1, "a"}, {2, "b"}}; //! piCout << m; // {1: a, 2: b} //! \endcode inline PIMap(std::initializer_list> init_list) { for (auto i: init_list) { insert(std::get<0>(i), std::get<1>(i)); } } //! \~english Assign operator. //! \~russian Оператор присваивания. inline PIMap & operator =(const PIMap & 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 & operator =(PIMap && other) { swap(other); return *this; } class iterator { friend class PIMap; private: iterator(const PIMap * v, ssize_t p): parent(v), pos(p) {} const PIMap * parent; ssize_t pos; public: iterator(): parent(nullptr), pos(0) {} const Key & key() const {return const_cast * >(parent)->_key(pos);} T & value() {return const_cast * >(parent)->_value(pos);} inline PIPair operator *() const { return PIPair(const_cast * >(parent)->_key(pos), const_cast * >(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; private: reverse_iterator(const PIMap * v, ssize_t p): parent(v), pos(p) {} const PIMap * parent; ssize_t pos; public: reverse_iterator(): parent(nullptr), pos(0) {} const Key & key() const {return const_cast * >(parent)->_key(pos);} T & value() const {return const_cast * >(parent)->_value(pos);} inline PIPair operator *() const { return PIPair(const_cast * >(parent)->_key(pos), const_cast * >(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; private: const_iterator(const PIMap * v, ssize_t p): parent(v), pos(p) {} const PIMap * 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 * >(parent)->_key(pos);} const T & value() const {return const_cast * >(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; private: const_reverse_iterator(const PIMap * v, ssize_t p): parent(v), pos(p) {} const PIMap * 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 first element of the reversed array. //! \~russian Обратный итератор на первый элемент. inline reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);} //! \~english Returns a reverse iterator to the element. //! following the last element of the reversed array. //! \~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 makeIterator() const {return PIMapIteratorConst(*this);} //! \relatesalso PIMapIterator inline PIMapIterator makeIterator() {return PIMapIterator(*this);} //! \relatesalso PIMapIteratorConstReverse inline PIMapIteratorConstReverse makeReverseIterator() const {return PIMapIteratorConstReverse(*this);} //! \relatesalso PIMapIteratorReverse inline PIMapIteratorReverse makeReverseIterator() {return PIMapIteratorReverse(*this);} //! \~english Number of elements in the container. //! \~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 elements in the container as 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 if the container has no elements. //! \~russian Проверяет пуст ли массив. //! \~\return //! \~english **true** if the container is empty, **false** otherwise //! \~russian **true** если массив пуст, **false** иначе. //! \~\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 if the container has elements. //! \~russian Проверяет не пуст ли массив. //! \~\return //! \~english **true** if the container is not empty, **false** otherwise //! \~russian **true** если массив не пуст, **false** иначе. //! \~\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 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); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; pim_content.push_back(T()); pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); return pim_content.back(); } //! \~english Same as \a value(). //! \~russian Синоним \a value(). //! \~\sa \a operator[](), \a value(), \a key() inline T at(const Key & key) const {return value(key);} //! \~english Remove element with key `key` from the array and return it. //! \~russian Удаляет элемент с ключом `key` из массива и возвращает его. inline T take(const Key & key) const { bool f(false); ssize_t i = _find(key, f); if (!f) return T(); T ret(pim_content[pim_index[i].index]); _remove(i); return ret; } //! \~english Inserts all elements in array `other` to this array with overwrite. //! \~russian Вставляет все элементы `other` этот массив с перезаписью. inline PIMap & operator <<(const PIMap & other) { #ifndef NDEBUG if (&other == this) { printf("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[0]); insert(other.pim_index[1].key, other.pim_content[1]); 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 Compare operator with array `m`. //! \~russian Оператор сравнения с массивом `m`. inline bool operator ==(const PIMap & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); } //! \~english Compare operator with array `m`. //! \~russian Оператор сравнения с массивом `m`. inline bool operator !=(const PIMap & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); } //! \~english Tests if element with key `key` exists in the array. //! \~russian Проверяет наличие элемента с ключом `key` в массиве. inline bool contains(const Key & key) const { bool f(false); _find(key, f); return f; } //! \~english Tests if element with value `value` exists in the array. //! \~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 & reserve(size_t new_size) { pim_content.reserve(new_size); pim_index.reserve(new_size); return *this; } //! \~english Remove element with key `key` from the array. //! \~russian Удаляет элемент с ключом `key` из массива. inline PIMap & remove(const Key & key) { bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this; } //! \~english Remove all elements in the array //! passes the test implemented by the provided function `test`. //! \~russian Удаляет все элементы, удовлетворяющие условию, //! заданному в передаваемой функции `test`. inline PIMap & removeWhere(std::function test) { for (int i = 0; i < pim_index.size_s(); ++i) { if (test(pim_index[i].key, pim_content[pim_index[i].index])) { _remove(i); --i; } } } //! \~english Same as \a remove(). //! \~russian Синоним функции \a remove(). inline PIMap & erase(const Key & key) { return remove(key); } //! \~english Clear array, remove all elements. //! \~russian Очищает массив, удаляет все элементы. //! \~\details //! \~\note //! \~english Reserved memory will not be released. //! \~russian Зарезервированная память не освободится. //! \~\sa \a resize() inline PIMap & clear() { pim_content.clear(); pim_index.clear(); return *this; } //! \~english Swaps array `v` other with this array. //! \~russian Меняет местами массив `v` с этим массивом. //! \~\details //! \~english This operation is very fast and never fails. //! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев. inline void swap(PIMap & other) { pim_content.swap(other.pim_content); pim_index.swap(other.pim_index); } inline PIMap & insert(const Key & key, const T & value) { bool f(false); ssize_t i = _find(key, f); if (f) { pim_content[pim_index[i].index] = value; } else { pim_content.push_back(value); pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); } return *this; } inline PIMap & insert(const Key & key, T && value) { bool f(false); ssize_t i = _find(key, f); if (f) { pim_content[pim_index[i].index] = std::move(value); } else { pim_content.push_back(std::move(value)); pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); } return *this; } inline PIMap & insert(const PIPair & pair) { bool f(false); ssize_t i = _find(pair.first, f); if (f) { pim_content[pim_index[i].index] = pair.second; } else { pim_content.push_back(pair.second); pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1)); } return *this; } inline PIMap & insert(PIPair && pair) { bool f(false); Key k(std::move(pair.first)); ssize_t i = _find(k, f); if (f) { pim_content[pim_index[i].index] = 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; } inline T value(const Key & key, const T & default_ = T()) const { bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index]; } inline PIVector values() const {return pim_content;} inline Key key(const T & value_, const Key & default_ = Key()) const { for (int i = 0; i < pim_index.size_s(); ++i) { if (pim_content[pim_index[i].index] == value_) { return pim_index[i].key; } } return default_; } inline PIVector keys() const { PIVector ret; ret.reserve(pim_index.size()); for (int i = 0; i < pim_index.size_s(); ++i) { ret << pim_index[i].key; } return ret; } inline void forEach(std::function f) const { for (int i = 0; i < pim_index.size_s(); ++i) { f(pim_index[i].key, pim_content[pim_index[i].index]); } } template inline PIMap map(std::function(const Key & key, const T & value)> f) const { PIMap ret; ret.reserve(size()); for (int i = 0; i < pim_index.size_s(); ++i) { ret.insert(f(pim_index[i].key, pim_content[pim_index[i].index])); } return ret; } template inline PIVector map(std::function f) const { PIVector ret; ret.reserve(size()); for (int i = 0; i < pim_index.size_s(); ++i) { ret << f(pim_index[i].key, pim_content[pim_index[i].index]); } return ret; } private: 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 friend PIBinaryStream

& operator >>(PIBinaryStream

& s, PIDeque::MapIndex> & v); template friend PIBinaryStream

& operator <<(PIBinaryStream

& s, const PIDeque::MapIndex> & v); inline ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const { ssize_t mid; 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) { 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(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(); return value_type(pim_index[index].key, pim_content[pim_index[index].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];} PIVector pim_content; PIDeque pim_index; }; //! \addtogroup Containers //! \{ //! \class PIMapIteratorConst //! \brief //! \~english Java-style iterator for \a PIMap. //! \~russian Итератор Java стиля для \a PIMap. //! \~\} //! \details //! \~english //! This class used to easy serial access keys and values in PIMap with read only permitions. //! Use constructor to create iterator, or use \a PIMap::makeIterator() //! \~russian //! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения. //! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator(). //! \~ //! \code //! PIMap 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 class PIMapIteratorConst { typedef PIMap MapType; public: inline PIMapIteratorConst(const PIMap & 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 //! This class used to easy serial reverse access keys and values in PIMap with read only permitions. //! Use constructor to create iterator, or use \a PIMap::makeReverseIterator(). //! \~russian //! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке только для чтения. //! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator(). //! \~ //! \code //! PIMap 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 class PIMapIteratorConstReverse { typedef PIMap MapType; public: inline PIMapIteratorConstReverse(const PIMap & 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 //! This class used to easy serial access keys and values in PIMap with write permitions. //! Use constructor to create iterator, or use \a PIMap::makeIterator() //! \~russian //! Этот класс используется для удобного перебора ключей и значений всего словаря с доступом на запись. //! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator(). //! \~ //! \code //! PIMap 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 class PIMapIterator { typedef PIMap MapType; public: inline PIMapIterator(PIMap & 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 //! This class used to easy serial reverse access keys and values in PIMap with write permitions. //! Use constructor to create iterator, or use \a PIMap::makeReverseIterator(). //! \~russian //! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись. //! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator(). //! \~ //! \code //! PIMap 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 class PIMapIteratorReverse { typedef PIMap MapType; public: inline PIMapIteratorReverse(PIMap & 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 inline std::ostream & operator <<(std::ostream & s, const PIMap & v) { s << "{"; bool first = true; for (typename PIMap::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 inline PICout operator <<(PICout s, const PIMap & v) { s.space(); s.saveAndSetControls(0); s << "{"; bool first = true; for (typename PIMap::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 inline void piSwap(PIMap & f, PIMap & s) {f.swap(s);} #endif // PIMAP_H