400 lines
14 KiB
C++
400 lines
14 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 PIMapIterator;
|
|
|
|
|
|
template <typename Key, typename T>
|
|
class PIMap {
|
|
template <typename Key1, typename T1> friend class PIMapIterator;
|
|
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:
|
|
PIMap() {;}
|
|
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
|
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
|
|
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
|
|
for (auto i: init_list) {
|
|
insert(std::get<0>(i), std::get<1>(i));
|
|
}
|
|
}
|
|
virtual ~PIMap() {;}
|
|
|
|
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;
|
|
}
|
|
|
|
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
|
|
swap(other);
|
|
return *this;
|
|
}
|
|
|
|
typedef T mapped_type;
|
|
typedef Key key_type;
|
|
typedef PIPair<Key, T> value_type;
|
|
|
|
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);}
|
|
};
|
|
|
|
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<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
|
|
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*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<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;
|
|
}
|
|
|
|
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);}
|
|
bool operator !=(const PIMap<Key, T> & 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<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
|
|
|
|
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
|
|
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
|
|
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
|
|
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
|
|
|
|
void swap(PIMap<Key, T> & other) {
|
|
pim_content.swap(other.pim_content);
|
|
pim_index.swap(other.pim_index);
|
|
}
|
|
|
|
PIMap<Key, T> & 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<Key, T> & 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<T> 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<Key> keys() const {
|
|
PIVector<Key> 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 <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);
|
|
|
|
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<T>(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<T> pim_content;
|
|
PIDeque<MapIndex> pim_index;
|
|
};
|
|
|
|
|
|
template <typename Key, typename T>
|
|
class PIMapIterator {
|
|
typedef PIMap<Key, T> MapType;
|
|
public:
|
|
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
|
|
if (rev) pos = m.size_s();
|
|
}
|
|
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
|
|
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
|
|
T & valueRef() const {return const_cast<MapType & >(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<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
|
|
|
|
template<typename Key, typename Type>
|
|
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
|
s.space();
|
|
s.setControl(0, true);
|
|
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.restoreControl();
|
|
return s;
|
|
}
|
|
|
|
template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
|
|
|
|
|
|
#endif // PIMAP_H
|