/*! \file pimap.h * \brief Associative array with custom types of key and value * * This file declares PIMap */ /* 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 PIByteArray & operator >>(PIByteArray & s, PIMap & v); template friend PIByteArray & operator <<(PIByteArray & s, const PIMap & v); template friend class PIMapIterator; public: PIMap() {} PIMap(const PIMap & other) {*this = other;} PIMap(PIMap && other) : pim_content(std::move(other.pim_content)) {} 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; 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(0), 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(0), 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(0), pos(0) {} const value_type operator *() const {return parent->_pair(pos);} const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;} 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);} mutable value_type cval; }; 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(0), pos(0) {} const value_type operator *() const {return parent->_pair(pos);} const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;} 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);} mutable value_type cval; }; 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);} T & operator [](const Key & key) { bool f(false); ssize_t i = _find(key, f); if (!f) pim_content.insert(i, PIPair(key, T())); return pim_content[i].second; } const T operator [](const Key & key) const { bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[i].second; return T(); } const T at(const Key & key) const {return (*this)[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_content.size_s(); ++i) insert(other.pim_content[i].first, other.pim_content[i].second); return *this; } bool operator ==(const PIMap & t) const {return (pim_content == t.pim_content);} bool operator !=(const PIMap & t) const {return (pim_content != t.pim_content);} 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);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(); return *this;} void swap(PIMap & other) { pim_content.swap(other.pim_content); } 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[i].second = value; } else { pim_content.insert(i, PIPair(key, value)); } 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[i].second = std::move(value); } else { // pim_content.push_back(std::move(value)); // pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); pim_content.insert(i, PIPair(key, std::move(value))); } return *this; } const 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[i].second; } PIVector values() const { PIVector ret; for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].second; return ret; } Key key(const T & value_, const Key & default_ = Key()) const { for (int i = 0; i < pim_content.size_s(); ++i) if (pim_content[i].second == value_) return pim_content[i].first; return default_; } PIVector keys() const { PIVector ret; for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].first; 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; } protected: // 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 PIByteArray & operator >>(PIByteArray & s, PIDeque::MapIndex> & v); // template friend PIByteArray & operator <<(PIByteArray & 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_content[mid].first) first = mid + 1; else if (key < pim_content[mid].first) last = mid - 1; else {found = true; return mid;} } found = false; return first; } ssize_t _find(const Key & k, bool & found) const { if (pim_content.isEmpty()) { found = false; return 0; } return binarySearch(0, pim_content.size_s() - 1, k, found); } void _remove(ssize_t index) { pim_content.remove(index); } const value_type _pair(ssize_t index) const { if (index < 0 || index >= pim_content.size_s()) return value_type(); return pim_content[index]; } Key & _key(ssize_t index) {return pim_content[index].first;} T & _value(ssize_t index) {return pim_content[index].second;} PIDeque> pim_content; }; 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->first << ": " << i->second; } 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->first << ": " << i->second; } s << "}"; s.restoreControl(); return s; } template inline void piSwap(PIMap & f, PIMap & s) {f.swap(s);} #endif // PIMAP_H