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);
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 Remove element with key `key` from the array and return it.
//! \~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 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);
const 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) {
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 & 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);
}
//! \~english Inserts value `value` with key `key` in the array.
//! \~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 & 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 & 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 value `pair` in the array.
//! \~russian Вставляет пару `pair` в массив.
//! \~\details
//! \~english The first element of the pair is the key, and the second is the value.
//! \~russian Первый элемент пары является ключом, а второй значением.
inline PIMap & insert(const PIPair & 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 & insert(PIPair && 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 an array of values of all elements
//! \~russian Возвращает массив значений всех эелметнов
inline PIVector 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 an array of keys of all elements
//! \~russian Возвращает массив ключей всех элементов
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;
}
//! \~english Execute function `void f(const Key & key, const T & value)` for every element in array.
//! \~russian Выполняет функцию `void f(const Key & key, const T & value)` для каждого элемента массива.
inline void forEach(std::function 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 Сreates a new map PIMap populated with the results
//! of calling a provided function `PIPair f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый словарь PIMap с результатом вызова указанной функции
//! `PIPair f(const Key & key, const T & value)` для каждого элемента массива.
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) {
const auto & mi(pim_index[i]);
ret.insert(f(mi.key, pim_content[mi.index]));
}
return ret;
}
//! \~english Сreates a new array PIVector populated with the results
//! of calling a provided function `ST f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый массив PIVector с результатом вызова указанной функции
//! `ST f(const Key & key, const T & value)` для каждого элемента массива.
template
inline PIVector map(std::function f) const {
PIVector 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 array with all elements
//! 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 filter(std::function test) const {
PIMap 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;
}
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 = 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(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]; }
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