//! \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 PIMapIterator; template class PIMap { template friend class PIMapIterator; template friend PIBinaryStream

& operator <<(PIBinaryStream

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

& operator >>(PIBinaryStream

& s, PIMap & v); public: PIMap() {;} PIMap(const PIMap & other) {*this = other;} PIMap(PIMap && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {} PIMap(std::initializer_list> init_list) { for (auto i: init_list) { insert(std::get<0>(i), std::get<1>(i)); } } virtual ~PIMap() {;} PIMap & operator =(const PIMap & other) { if (this == &other) return *this; clear(); pim_content = other.pim_content; pim_index = other.pim_index; return *this; } PIMap & operator =(PIMap && other) { swap(other); return *this; } typedef T mapped_type; typedef Key key_type; typedef PIPair value_type; 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);} }; iterator begin() {return iterator(this, 0);} iterator end() {return iterator(this, size());} const_iterator begin() const {return const_iterator(this, 0);} const_iterator end() const {return const_iterator(this, size());} const_iterator constBegin() const {return const_iterator(this, 0);} const_iterator constEnd() const {return const_iterator(this, size());} reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);} reverse_iterator rend() {return reverse_iterator(this, -1);} const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);} const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);} const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);} const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);} PIMapIterator makeIterator() const {return PIMapIterator(*this);} PIMapIterator makeReverseIterator() const {return PIMapIterator(*this, true);} size_t size() const {return pim_content.size();} int size_s() const {return pim_content.size_s();} size_t length() const {return pim_content.size();} bool isEmpty() const {return (pim_content.size() == 0);} bool isNotEmpty() const {return (pim_content.size() > 0);} 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(); } T at(const Key & key) const {return value(key);} 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; } bool operator ==(const PIMap & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);} bool operator !=(const PIMap & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);} bool contains(const Key & key) const {bool f(false); _find(key, f); return f;} PIMap & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;} PIMap & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;} PIMap & remove(const Key & key) {return removeOne(key);} PIMap & erase(const Key & key) {return removeOne(key);} PIMap & clear() {pim_content.clear(); pim_index.clear(); return *this;} void swap(PIMap & other) { pim_content.swap(other.pim_content); pim_index.swap(other.pim_index); } PIMap & insert(const Key & key, const T & value) { bool f(false); ssize_t i = _find(key, f); //piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value; 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; } PIMap & insert(const Key & key, T && value) { bool f(false); ssize_t i = _find(key, f); //piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value; 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; } 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];} PIVector values() const {return pim_content;} 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_;} PIVector keys() const { PIVector ret; for (int i = 0; i < pim_index.size_s(); ++i) ret << pim_index[i].key; return ret; } // void dump() { // piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:"; // for (size_t i = 0; i < pim_content.size(); ++i) // piCout << PICoutManipulators::Tab << i << ":" << pim_content[i]; // piCout << "index:"; // for (size_t i = 0; i < pim_index.size(); ++i) // piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index; // } private: struct MapIndex { MapIndex(Key k = Key(), size_t i = 0): key(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); 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; } 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); } void _remove(ssize_t index) { //if (index >= pim_index.size()) return; 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()); } const value_type _pair(ssize_t index) const { if (index < 0 || index >= pim_index.size_s()) return value_type(); //piCout << "_pair" << index << pim_index[index].index; return value_type(pim_index[index].key, pim_content[pim_index[index].index]); } Key & _key(ssize_t index) {return pim_index[index].key;} T & _value(ssize_t index) {return pim_content[pim_index[index].index];} PIVector pim_content; PIDeque pim_index; }; template class PIMapIterator { typedef PIMap MapType; public: PIMapIterator(const PIMap & map, bool reverse = false): m(map), pos(-1), rev(reverse) { if (rev) pos = m.size_s(); } const Key & key() const {return const_cast(m)._key(pos);} const T & value() const {return const_cast(m)._value(pos);} T & valueRef() const {return const_cast(m)._value(pos);} inline bool hasNext() const { if (rev) { return pos > 0; } else { return pos < (m.size_s() - 1); } return false; } inline bool next() { if (rev) { --pos; return pos >= 0; } else { ++pos; return pos < m.size_s(); } return false; } inline void reset() { if (rev) { pos = m.size_s(); } else { pos = -1; } } private: const MapType & m; ssize_t pos; bool rev; }; #ifdef PIP_STD_IOSTREAM 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 template inline PICout operator <<(PICout s, const PIMap & v) { s.space(); s.setControl(0, true); 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.restoreControl(); return s; } template inline void piSwap(PIMap & f, PIMap & s) {f.swap(s);} #endif // PIMAP_H