/**************************************************************************** ** ** https://www.qxorm.com/ ** Copyright (C) 2013 Lionel Marty (contact@qxorm.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 Lionel Marty ** ** 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 : ** contact@qxorm.com ** ****************************************************************************/ namespace qx { template QxCollection::QxCollection() : IxCollection(), m_batch(false) { } template QxCollection::QxCollection(const QxCollection & other) : IxCollection(), m_batch(false) { cloneCollection(this, other); } template QxCollection::~QxCollection() { } template QxCollection & QxCollection::operator= (const QxCollection & other) { if (this != (& other)) { cloneCollection(this, other); } return (* this); } template bool QxCollection::operator== (const QxCollection & other) const { return isSameCollection(this, other); } template bool QxCollection::operator!= (const QxCollection & other) const { return (! isSameCollection(this, other)); } template void QxCollection::cloneCollection(QxCollection * pClone, const QxCollection & 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 bool QxCollection::isSameCollection(const QxCollection * p1, const QxCollection & 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 void QxCollection::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 QxCollection::iterator QxCollection::begin() { QMutexLocker locker(& m_mutex); return m_list.begin(); } template typename QxCollection::iterator QxCollection::end() { QMutexLocker locker(& m_mutex); return m_list.end(); } template typename QxCollection::const_iterator QxCollection::begin() const { QMutexLocker locker(& m_mutex); return m_list.begin(); } template typename QxCollection::const_iterator QxCollection::end() const { QMutexLocker locker(& m_mutex); return m_list.end(); } #if (QT_VERSION >= 0x050600) template typename QxCollection::reverse_iterator QxCollection::rbegin() { QMutexLocker locker(& m_mutex); return m_list.rbegin(); } template typename QxCollection::reverse_iterator QxCollection::rend() { QMutexLocker locker(& m_mutex); return m_list.rend(); } template typename QxCollection::const_reverse_iterator QxCollection::rbegin() const { QMutexLocker locker(& m_mutex); return m_list.rbegin(); } template typename QxCollection::const_reverse_iterator QxCollection::rend() const { QMutexLocker locker(& m_mutex); return m_list.rend(); } #endif // (QT_VERSION >= 0x050600) template void QxCollection::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 void QxCollection::reverse() { { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); std::reverse(m_list.begin(), m_list.end()); } updateHashPosition(); } template void QxCollection::clear() { QMutexLocker locker(& m_mutex); m_hash.clear(); m_list.clear(); } template long QxCollection::count() const { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); return static_cast(m_list.size()); } template long QxCollection::size() const { return this->count(); } template bool QxCollection::contains(const Key & key) const { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); return (m_hash.contains(key)); } template bool QxCollection::exist(const Key & key) const { return this->contains(key); } template bool QxCollection::empty() const { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); return m_list.isEmpty(); } template bool QxCollection::push_back(const Key & key, const Value & value) { return this->insert(key, value); } template bool QxCollection::push_front(const Key & key, const Value & value) { return this->insert(0, key, value); } template bool QxCollection::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 bool QxCollection::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 bool QxCollection::insert(const QxCollection & 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 bool QxCollection::insert(long index, const QxCollection & 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 bool QxCollection::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 bool QxCollection::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 bool QxCollection::move(long indexFrom, long indexTo) { return swap(indexFrom, indexTo); } template bool QxCollection::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 bool QxCollection::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 bool QxCollection::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 bool QxCollection::removeFirst() { return this->removeByIndex(0); } template bool QxCollection::removeLast() { return this->removeByIndex(size() - 1); } template typename QxCollection::const_reference_value QxCollection::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 QxCollection::const_reference_value QxCollection::getByIndex(long index) const { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); qAssert((index >= 0) && (index < static_cast(m_list.size()))); qAssert(m_hash.value(m_list.at(index).first, -1) == index); return m_list.at(index).second; } template typename QxCollection::const_reference_value QxCollection::getFirst() const { qAssert(! empty()); QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); return m_list.at(0).second; } template typename QxCollection::const_reference_value QxCollection::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 QxCollection::const_reference_key QxCollection::getKeyByIndex(long index) const { QMutexLocker locker(& m_mutex); qAssert(m_list.size() == m_hash.size()); qAssert((index >= 0) && (index < static_cast(m_list.size()))); qAssert(m_hash.value(m_list.at(index).first, -1) == index); return m_list.at(index).first; } template void QxCollection::sortByKey(bool bAscending /* = true */) { if (bAscending) { QMutexLocker locker(& m_mutex); std::sort(m_list.begin(), m_list.end(), (& compareKeyValue::value || qx::trait::is_smart_ptr::value, 0>::compareByKeyAscending)); } else { QMutexLocker locker(& m_mutex); std::sort(m_list.begin(), m_list.end(), (& compareKeyValue::value || qx::trait::is_smart_ptr::value, 0>::compareByKeyDescending)); } updateHashPosition(0, -1, true); } template void QxCollection::sortByValue(bool bAscending /* = true */) { if (bAscending) { QMutexLocker locker(& m_mutex); std::sort(m_list.begin(), m_list.end(), (& compareKeyValue::value || qx::trait::is_smart_ptr::value, 0>::compareByValueAscending)); } else { QMutexLocker locker(& m_mutex); std::sort(m_list.begin(), m_list.end(), (& compareKeyValue::value || qx::trait::is_smart_ptr::value, 0>::compareByValueDescending)); } updateHashPosition(0, -1, true); } } // namespace qx template QDataStream & operator<< (QDataStream & stream, const qx::QxCollection & 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 QDataStream & operator>> (QDataStream & stream, qx::QxCollection & 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; }