616 lines
17 KiB
C++
616 lines
17 KiB
C++
/****************************************************************************
|
|
**
|
|
** https://www.qxorm.com/
|
|
** Copyright (C) 2013 XDL Team (ic-east.com)
|
|
**
|
|
** This file is part of the QxOrm library
|
|
**
|
|
** This software is provided 'as-is', without any express or implied
|
|
** warranty. In no event will the authors be held liable for any
|
|
** damages arising from the use of this software
|
|
**
|
|
** Commercial Usage
|
|
** Licensees holding valid commercial QxOrm licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and XDL Team
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file 'license.gpl3.txt' included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met : http://www.gnu.org/copyleft/gpl.html
|
|
**
|
|
** If you are unsure which license is appropriate for your use, or
|
|
** if you have questions regarding the use of this file, please contact :
|
|
** ic-east.com
|
|
**
|
|
****************************************************************************/
|
|
|
|
namespace qx
|
|
{
|
|
|
|
template <typename Key, typename Value>
|
|
QxCollection<Key, Value>::QxCollection() : IxCollection(), m_batch(false)
|
|
{
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
QxCollection<Key, Value>::QxCollection(const QxCollection<Key, Value> &other) : IxCollection(), m_batch(false)
|
|
{
|
|
cloneCollection(this, other);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
QxCollection<Key, Value>::~QxCollection()
|
|
{
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
QxCollection<Key, Value> &QxCollection<Key, Value>::operator=(const QxCollection<Key, Value> &other)
|
|
{
|
|
if (this != (&other))
|
|
{
|
|
cloneCollection(this, other);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::operator==(const QxCollection<Key, Value> &other) const
|
|
{
|
|
return isSameCollection(this, other);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::operator!=(const QxCollection<Key, Value> &other) const
|
|
{
|
|
return (!isSameCollection(this, other));
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::cloneCollection(QxCollection<Key, Value> *pClone, const QxCollection<Key, Value> &pRef)
|
|
{
|
|
if (!pClone)
|
|
{
|
|
return;
|
|
}
|
|
if (pClone == (&pRef))
|
|
{
|
|
return;
|
|
}
|
|
QMutexLocker locker1(&pRef.m_mutex);
|
|
QMutexLocker locker2(&pClone->m_mutex);
|
|
qAssert(pRef.m_list.size() == pRef.m_hash.size());
|
|
pClone->m_list = pRef.m_list;
|
|
pClone->m_hash = pRef.m_hash;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::isSameCollection(const QxCollection<Key, Value> *p1, const QxCollection<Key, Value> &p2) const
|
|
{
|
|
if (!p1)
|
|
{
|
|
return false;
|
|
}
|
|
if (p1 == (&p2))
|
|
{
|
|
return true;
|
|
}
|
|
if (p1->size() != p2.size())
|
|
{
|
|
return false;
|
|
}
|
|
QMutexLocker locker1(&p2.m_mutex);
|
|
QMutexLocker locker2(&p1->m_mutex);
|
|
qAssert(p2.m_list.size() == p2.m_hash.size());
|
|
return ((p1->m_list == p2.m_list) && (p1->m_hash == p2.m_hash));
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::updateHashPosition(long from /* = 0 */, long to /* = -1 */, bool check /* = false */)
|
|
{
|
|
if (m_batch)
|
|
{
|
|
return;
|
|
}
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
if (to == -1)
|
|
{
|
|
to = (m_list.size() - 1);
|
|
}
|
|
if ((from < 0) || (to >= m_list.size()) || (from > to))
|
|
{
|
|
return;
|
|
}
|
|
for (long idx = from; idx <= to; idx++)
|
|
{
|
|
const Key &key = m_list.at(idx).first;
|
|
m_hash.insert(key, idx);
|
|
}
|
|
if (check)
|
|
{
|
|
qAssert(m_list.size() == m_hash.size());
|
|
}
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::iterator QxCollection<Key, Value>::begin()
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.begin();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::iterator QxCollection<Key, Value>::end()
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.end();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_iterator QxCollection<Key, Value>::begin() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.begin();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_iterator QxCollection<Key, Value>::end() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.end();
|
|
}
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::reverse_iterator QxCollection<Key, Value>::rbegin()
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.rbegin();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::reverse_iterator QxCollection<Key, Value>::rend()
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.rend();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reverse_iterator QxCollection<Key, Value>::rbegin() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.rbegin();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reverse_iterator QxCollection<Key, Value>::rend() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
return m_list.rend();
|
|
}
|
|
|
|
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::reserve(long size)
|
|
{
|
|
if (size <= 0)
|
|
{
|
|
return;
|
|
}
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
m_list.reserve(size);
|
|
m_hash.reserve(size);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::reverse()
|
|
{
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
std::reverse(m_list.begin(), m_list.end());
|
|
}
|
|
updateHashPosition();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::clear()
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
m_hash.clear();
|
|
m_list.clear();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
long QxCollection<Key, Value>::count() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return static_cast<long>(m_list.size());
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
long QxCollection<Key, Value>::size() const
|
|
{
|
|
return this->count();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::contains(const Key &key) const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return (m_hash.contains(key));
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::exist(const Key &key) const
|
|
{
|
|
return this->contains(key);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::empty() const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return m_list.isEmpty();
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::push_back(const Key &key, const Value &value)
|
|
{
|
|
return this->insert(key, value);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::push_front(const Key &key, const Value &value)
|
|
{
|
|
return this->insert(0, key, value);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::insert(const Key &key, const Value &value)
|
|
{
|
|
qAssert(!exist(key));
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
m_list.append(qMakePair(key, value));
|
|
m_hash.insert(key, (m_list.size() - 1));
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::insert(long index, const Key &key, const Value &value)
|
|
{
|
|
qAssert(!exist(key));
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
if (index >= size())
|
|
{
|
|
return this->insert(key, value);
|
|
}
|
|
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
m_list.insert(index, qMakePair(key, value));
|
|
m_hash.insert(key, index);
|
|
}
|
|
|
|
updateHashPosition(index);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::insert(const QxCollection<Key, Value> &other)
|
|
{
|
|
{
|
|
if (this == (&other))
|
|
{
|
|
return false;
|
|
}
|
|
QMutexLocker locker1(&m_mutex);
|
|
QMutexLocker locker2(&other.m_mutex);
|
|
m_list.append(other.m_list);
|
|
m_hash.unite(other.m_hash);
|
|
}
|
|
|
|
updateHashPosition(0, -1, true);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::insert(long index, const QxCollection<Key, Value> &other)
|
|
{
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
if ((index >= size()) && (index != 0))
|
|
{
|
|
index = (size() - 1);
|
|
}
|
|
if (this == (&other))
|
|
{
|
|
return false;
|
|
}
|
|
QMutexLocker locker1(&other.m_mutex);
|
|
|
|
{
|
|
QMutexLocker locker2(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
m_batch = true;
|
|
}
|
|
|
|
for (long l = 0; l < other.size(); l++)
|
|
{
|
|
const type_pair_key_value &pair = other.m_list.at(l);
|
|
this->insert((index + l), pair.first, pair.second);
|
|
}
|
|
|
|
{
|
|
QMutexLocker locker3(&m_mutex);
|
|
m_batch = false;
|
|
}
|
|
updateHashPosition(index);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::replace(long index, const Key &key, const Value &value)
|
|
{
|
|
qAssert(!exist(key));
|
|
QMutexLocker locker(&m_mutex);
|
|
m_hash.remove(m_list.at(index).first);
|
|
m_list.replace(index, qMakePair(key, value));
|
|
m_hash.insert(key, index);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::swap(long index1, long index2)
|
|
{
|
|
if (index1 < 0 || index1 >= size())
|
|
{
|
|
return false;
|
|
}
|
|
if (index2 < 0 || index2 >= size())
|
|
{
|
|
return false;
|
|
}
|
|
if (index1 == index2)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QMutexLocker locker(&m_mutex);
|
|
const Key &key1 = m_list.at(index1).first;
|
|
const Key &key2 = m_list.at(index2).first;
|
|
m_hash.insert(key1, index2);
|
|
m_hash.insert(key2, index1);
|
|
m_list.swap(index1, index2);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::move(long indexFrom, long indexTo)
|
|
{
|
|
return swap(indexFrom, indexTo);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::removeByKey(const Key &key)
|
|
{
|
|
qAssert(exist(key));
|
|
long pos = 0;
|
|
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
pos = m_hash.value(key, -1);
|
|
if ((pos < 0) || (pos >= m_list.size()))
|
|
{
|
|
return false;
|
|
}
|
|
qAssert(m_list.at(pos).first == key);
|
|
m_hash.remove(key);
|
|
m_list.removeAt(pos);
|
|
}
|
|
|
|
updateHashPosition(pos, -1, true);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::removeByIndex(long index)
|
|
{
|
|
if (index < 0 || index >= size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
const Key &key = m_list.at(index).first;
|
|
qAssert(m_hash.value(key, -1) == index);
|
|
m_hash.remove(key);
|
|
m_list.removeAt(index);
|
|
}
|
|
|
|
updateHashPosition(index, -1, true);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::removeByIndex(long first, long last)
|
|
{
|
|
if (first < 0 || first >= size())
|
|
{
|
|
return false;
|
|
}
|
|
if (last < 0 || last >= size())
|
|
{
|
|
return false;
|
|
}
|
|
if (first > last)
|
|
{
|
|
return false;
|
|
}
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
m_batch = true;
|
|
}
|
|
for (long idx = first; idx <= last; idx++)
|
|
{
|
|
removeByIndex(idx);
|
|
}
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
m_batch = false;
|
|
}
|
|
updateHashPosition(first);
|
|
return true;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::removeFirst()
|
|
{
|
|
return this->removeByIndex(0);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
bool QxCollection<Key, Value>::removeLast()
|
|
{
|
|
return this->removeByIndex(size() - 1);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reference_value QxCollection<Key, Value>::getByKey(const Key &key) const
|
|
{
|
|
qAssert(exist(key));
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
const type_pair_key_value &pair = m_list.at(m_hash.value(key, -1));
|
|
qAssert(pair.first == key);
|
|
return pair.second;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reference_value QxCollection<Key, Value>::getByIndex(long index) const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
qAssert((index >= 0) && (index < static_cast<long>(m_list.size())));
|
|
qAssert(m_hash.value(m_list.at(index).first, -1) == index);
|
|
return m_list.at(index).second;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reference_value QxCollection<Key, Value>::getFirst() const
|
|
{
|
|
qAssert(!empty());
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return m_list.at(0).second;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reference_value QxCollection<Key, Value>::getLast() const
|
|
{
|
|
qAssert(!empty());
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
return m_list.at(m_list.size() - 1).second;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
typename QxCollection<Key, Value>::const_reference_key QxCollection<Key, Value>::getKeyByIndex(long index) const
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
qAssert(m_list.size() == m_hash.size());
|
|
qAssert((index >= 0) && (index < static_cast<long>(m_list.size())));
|
|
qAssert(m_hash.value(m_list.at(index).first, -1) == index);
|
|
return m_list.at(index).first;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::sortByKey(bool bAscending /* = true */)
|
|
{
|
|
if (bAscending)
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer<Key>::value || qx::trait::is_smart_ptr<Key>::value, 0 > ::compareByKeyAscending));
|
|
}
|
|
else
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer<Key>::value || qx::trait::is_smart_ptr<Key>::value, 0 > ::compareByKeyDescending));
|
|
}
|
|
updateHashPosition(0, -1, true);
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
void QxCollection<Key, Value>::sortByValue(bool bAscending /* = true */)
|
|
{
|
|
if (bAscending)
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer<Value>::value || qx::trait::is_smart_ptr<Value>::value, 0 > ::compareByValueAscending));
|
|
}
|
|
else
|
|
{
|
|
QMutexLocker locker(&m_mutex);
|
|
std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer<Value>::value || qx::trait::is_smart_ptr<Value>::value, 0 > ::compareByValueDescending));
|
|
}
|
|
updateHashPosition(0, -1, true);
|
|
}
|
|
|
|
} // namespace qx
|
|
|
|
template <typename Key, typename Value>
|
|
QDataStream &operator<<(QDataStream &stream, const qx::QxCollection<Key, Value> &t)
|
|
{
|
|
long lCount = t.count();
|
|
stream << (qint32)(lCount);
|
|
|
|
for (long l = 0; l < lCount; l++)
|
|
{
|
|
stream << t.getKeyByIndex(l);
|
|
stream << t.getByIndex(l);
|
|
}
|
|
|
|
return stream;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
QDataStream &operator>>(QDataStream &stream, qx::QxCollection<Key, Value> &t)
|
|
{
|
|
qint32 lCount = 0;
|
|
stream >> lCount;
|
|
t.clear();
|
|
t.reserve(lCount);
|
|
|
|
for (qint32 l = 0; l < lCount; l++)
|
|
{
|
|
Key key;
|
|
stream >> key;
|
|
Value value;
|
|
stream >> value;
|
|
t.insert(key, value);
|
|
}
|
|
|
|
return stream;
|
|
}
|