948 lines
33 KiB
C++
948 lines
33 KiB
C++
//! \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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef PIMAP_H
|
||
#define PIMAP_H
|
||
|
||
#include "pivector.h"
|
||
#include "pideque.h"
|
||
#include "pipair.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 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 <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 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<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 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 <PIString, PIString> m;
|
||
//! m[] =
|
||
//! piCout << m; //
|
||
//! \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);}
|
||
|
||
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<Key, T> & operator <<(const PIMap<Key, T> & 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<Key, T> & 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<Key, T> & 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<Key, T> & 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<Key, T> & 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<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> 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<Key, T> & 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<Key, T> & 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<Key, T> & other) {
|
||
pim_content.swap(other.pim_content);
|
||
pim_index.swap(other.pim_index);
|
||
}
|
||
|
||
inline PIMap<Key, T> & 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<Key, T> & 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<Key, T> & insert(const PIPair<Key, T> & 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<Key, T> & insert(PIPair<Key, T> && 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<T> 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<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;
|
||
}
|
||
|
||
inline void forEach(std::function<void(const Key & key, const T & value)> f) const {
|
||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||
f(pim_index[i].key, pim_content[pim_index[i].index]);
|
||
}
|
||
}
|
||
|
||
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) {
|
||
ret.insert(f(pim_index[i].key, pim_content[pim_index[i].index]));
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
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) {
|
||
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 <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);
|
||
|
||
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<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();
|
||
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<T> pim_content;
|
||
PIDeque<MapIndex> 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<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
|
||
//! 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<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
|
||
//! 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<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
|
||
//! 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<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
|