mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 19:02:53 +00:00
482 lines
14 KiB
C++
482 lines
14 KiB
C++
/***************************************************************************
|
|
Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifndef KDEVPLATFORM_SETREPOSITORY_H
|
|
#define KDEVPLATFORM_SETREPOSITORY_H
|
|
|
|
#include "basicsetrepository.h"
|
|
#include <QtCore/QMutex>
|
|
#include <list>
|
|
#include <language/duchain/indexedstring.h>
|
|
|
|
/**
|
|
* This header defines convenience-class that allow handling set-repositories using the represented higher-level objects instead
|
|
* of indices to them.
|
|
* */
|
|
|
|
|
|
namespace Utils {
|
|
/**
|
|
* Use this class to conveniently iterate over the items in a set.
|
|
* @param T The type the indices will be converted to
|
|
* @param Conversion Should be a class that has a toIndex member function that takes an object of type T as parameter, and returns an index,
|
|
* and a toItem member function that takes an index, and returns an item of type T.
|
|
* */
|
|
template<class T, class Conversion>
|
|
class ConvenientIterator : public Conversion {
|
|
public:
|
|
ConvenientIterator(Set::Iterator it=Set::Iterator()) : m_it(it) {
|
|
}
|
|
ConvenientIterator(const Set& set) : m_it(set.iterator()) {
|
|
}
|
|
|
|
operator bool() const {
|
|
return m_it;
|
|
}
|
|
|
|
ConvenientIterator& operator++() {
|
|
++m_it;
|
|
return *this;
|
|
}
|
|
|
|
T operator*() const {
|
|
return Conversion::toItem(*m_it);
|
|
}
|
|
|
|
const T& ref() const {
|
|
return Conversion::toItem(*m_it);
|
|
}
|
|
|
|
uint index() const {
|
|
return *m_it;
|
|
}
|
|
|
|
private:
|
|
Set::Iterator m_it;
|
|
};
|
|
|
|
struct DummyLocker {
|
|
};
|
|
|
|
template<class T>
|
|
struct IdentityConversion {
|
|
static T toIndex(const T& t) {
|
|
return t;
|
|
}
|
|
static T toItem(const T& t) {
|
|
return t;
|
|
}
|
|
};
|
|
|
|
///This is a virtual set-node that allows conveniently iterating through the tree-structure,
|
|
///accessing the contained items directly, and accessing the ranges.
|
|
template<class T, class Conversion, class StaticRepository>
|
|
class VirtualSetNode {
|
|
public:
|
|
inline VirtualSetNode(const SetNodeData* data = 0) : m_data(data) {
|
|
}
|
|
|
|
inline bool isValid() const {
|
|
return (bool)m_data;
|
|
}
|
|
|
|
///If this returns false, a left and a right node are available.
|
|
///If this returns true, this node represents a single item, that can be retrieved by calling item() or operator*.
|
|
inline bool isFinalNode() const {
|
|
return m_data->leftNode() == 0;
|
|
}
|
|
|
|
inline T firstItem() const {
|
|
return Conversion::toItem(start());
|
|
}
|
|
|
|
inline T lastItem() const {
|
|
return Conversion::toItem(end()-1);
|
|
}
|
|
|
|
inline T operator*() const {
|
|
return Conversion::toItem(start());
|
|
}
|
|
|
|
inline VirtualSetNode<T, Conversion, StaticRepository> leftChild() const {
|
|
if(m_data->leftNode())
|
|
return StaticRepository::repository()->nodeFromIndex(m_data->leftNode());
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
inline VirtualSetNode<T, Conversion, StaticRepository> rightChild() const {
|
|
if(m_data->rightNode())
|
|
return StaticRepository::repository()->nodeFromIndex(m_data->rightNode());
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
///Returns the start of this node's range. If this is a final node, the length of the range is 1.
|
|
inline uint start() const {
|
|
return m_data->start();
|
|
}
|
|
|
|
///Returns the end of this node's range.
|
|
inline uint end() const {
|
|
return m_data->end();
|
|
}
|
|
|
|
private:
|
|
const SetNodeData* m_data;
|
|
};
|
|
|
|
template<class T, class Conversion, class StaticRepository, bool doReferenceCounting = false, class StaticAccessLocker = DummyLocker>
|
|
class StorableSet : public Conversion {
|
|
public:
|
|
|
|
typedef VirtualSetNode<T, Conversion, StaticRepository> Node;
|
|
|
|
StorableSet(const StorableSet& rhs) : m_setIndex(rhs.m_setIndex) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
if(doReferenceCounting)
|
|
set().staticRef();
|
|
}
|
|
|
|
StorableSet(const std::set<uint>& indices) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
m_setIndex = StaticRepository::repository()->createSet(indices).setIndex();
|
|
if(doReferenceCounting)
|
|
set().staticRef();
|
|
}
|
|
|
|
StorableSet() : m_setIndex(0) {
|
|
}
|
|
|
|
~StorableSet() {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
if(doReferenceCounting)
|
|
set().staticUnref();
|
|
}
|
|
|
|
void insert(const T& t) {
|
|
insertIndex(Conversion::toIndex(t));
|
|
}
|
|
|
|
bool isEmpty() const {
|
|
return m_setIndex == 0;
|
|
}
|
|
|
|
uint count() const {
|
|
return set().count();
|
|
}
|
|
|
|
void insertIndex(uint index) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
Set oldSet(set);
|
|
Set addedSet = StaticRepository::repository()->createSet(index);
|
|
if(doReferenceCounting)
|
|
addedSet.staticRef();
|
|
set += addedSet;
|
|
m_setIndex = set.setIndex();
|
|
|
|
if(doReferenceCounting) {
|
|
set.staticRef();
|
|
oldSet.staticUnref();
|
|
addedSet.staticUnref();
|
|
}
|
|
}
|
|
|
|
void remove(const T& t) {
|
|
removeIndex(Conversion::toIndex(t));
|
|
}
|
|
|
|
void removeIndex(uint index) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
Set oldSet(set);
|
|
Set removedSet = StaticRepository::repository()->createSet(index);
|
|
if(doReferenceCounting) {
|
|
removedSet.staticRef();
|
|
}
|
|
set -= removedSet;
|
|
m_setIndex = set.setIndex();
|
|
|
|
if(doReferenceCounting) {
|
|
set.staticRef();
|
|
oldSet.staticUnref();
|
|
removedSet.staticUnref();
|
|
}
|
|
}
|
|
|
|
Set set() const {
|
|
return Set(m_setIndex, StaticRepository::repository());
|
|
}
|
|
|
|
bool contains(const T& item) const {
|
|
return containsIndex(Conversion::toIndex(item));
|
|
}
|
|
|
|
bool containsIndex(uint index) const {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
return set.contains(index);
|
|
}
|
|
|
|
StorableSet& operator +=(const StorableSet& rhs) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
Set oldSet(set);
|
|
Set otherSet(rhs.m_setIndex, StaticRepository::repository());
|
|
set += otherSet;
|
|
m_setIndex = set.setIndex();
|
|
|
|
if(doReferenceCounting) {
|
|
set.staticRef();
|
|
oldSet.staticUnref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
StorableSet& operator -=(const StorableSet& rhs) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
Set oldSet(set);
|
|
Set otherSet(rhs.m_setIndex, StaticRepository::repository());
|
|
set -= otherSet;
|
|
m_setIndex = set.setIndex();
|
|
|
|
if(doReferenceCounting) {
|
|
set.staticRef();
|
|
oldSet.staticUnref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
StorableSet& operator &=(const StorableSet& rhs) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
Set set(m_setIndex, StaticRepository::repository());
|
|
Set oldSet(set);
|
|
Set otherSet(rhs.m_setIndex, StaticRepository::repository());
|
|
set &= otherSet;
|
|
m_setIndex = set.setIndex();
|
|
|
|
if(doReferenceCounting) {
|
|
set.staticRef();
|
|
oldSet.staticUnref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
StorableSet& operator=(const StorableSet& rhs) {
|
|
StaticAccessLocker lock;
|
|
Q_UNUSED(lock);
|
|
if(doReferenceCounting)
|
|
set().staticUnref();
|
|
m_setIndex = rhs.m_setIndex;
|
|
if(doReferenceCounting)
|
|
set().staticRef();
|
|
return *this;
|
|
}
|
|
|
|
StorableSet operator +(const StorableSet& rhs) const {
|
|
StorableSet ret(*this);
|
|
ret += rhs;
|
|
return ret;
|
|
}
|
|
|
|
StorableSet operator -(const StorableSet& rhs) const {
|
|
StorableSet ret(*this);
|
|
ret -= rhs;
|
|
return ret;
|
|
}
|
|
|
|
StorableSet operator &(const StorableSet& rhs) const {
|
|
StorableSet ret(*this);
|
|
ret &= rhs;
|
|
return ret;
|
|
}
|
|
|
|
bool operator==(const StorableSet& rhs) const {
|
|
return m_setIndex == rhs.m_setIndex;
|
|
}
|
|
|
|
typedef ConvenientIterator<T, Conversion> Iterator;
|
|
|
|
Iterator iterator() const {
|
|
return ConvenientIterator<T, Conversion>(set());
|
|
}
|
|
|
|
Node node() const {
|
|
return Node(StaticRepository::repository()->nodeFromIndex(m_setIndex));
|
|
}
|
|
|
|
uint setIndex() const {
|
|
return m_setIndex;
|
|
}
|
|
|
|
private:
|
|
|
|
uint m_setIndex;
|
|
};
|
|
|
|
template<class T, class Conversion, class StaticRepository, bool doReferenceCounting, class StaticAccessLocker>
|
|
uint qHash(const StorableSet<T, Conversion, StaticRepository, doReferenceCounting, StaticAccessLocker>& set) {
|
|
return set.setIndex();
|
|
}
|
|
/** This is a helper-class that helps inserting a bunch of items into a set without caring about grouping them together.
|
|
*
|
|
* It creates a much better tree-structure if many items are inserted at one time, and this class helps doing that in
|
|
* cases where there is no better choice then storing a temporary list of items and inserting them all at once.
|
|
*
|
|
* This set will then care about really inserting them into the repository once the real set is requested.
|
|
*
|
|
* @todo eventually make this unnecessary
|
|
*
|
|
* @param T Should be the type that should be dealt
|
|
* @param Conversion Should be a class that has a toIndex member function that takes an object of type T as parameter, and returns an index,
|
|
* and a toItem member function that takes an index, and returns an item of type T.
|
|
**/
|
|
template<class T, class Conversion>
|
|
class LazySet : public Conversion {
|
|
public:
|
|
/** @param rep The repository the set should belong/belongs to
|
|
* @param lockBeforeAccess If this is nonzero, the given mutex will be locked before each modification to the repository.
|
|
* @param basicSet If this is explicitly given, the given set will be used as base. However it will not be changed.
|
|
*
|
|
* @warning Watch for deadlocks, never use this class while the mutex given through lockBeforeAccess is locked
|
|
*/
|
|
LazySet(BasicSetRepository* rep, QMutex* lockBeforeAccess = 0, const Set& basicSet = Set()) : m_rep(rep), m_set(basicSet), m_lockBeforeAccess(lockBeforeAccess) {
|
|
}
|
|
|
|
void insert(const T& t) {
|
|
if(!m_temporaryRemoveIndices.empty())
|
|
apply();
|
|
m_temporaryIndices.insert(Conversion::toIndex(t));
|
|
}
|
|
|
|
void insertIndex(uint index) {
|
|
if(!m_temporaryRemoveIndices.empty())
|
|
apply();
|
|
m_temporaryIndices.insert(index);
|
|
}
|
|
|
|
void remove(const T& t) {
|
|
if(!m_temporaryIndices.empty())
|
|
apply();
|
|
m_temporaryRemoveIndices.insert(Conversion::toIndex(t));
|
|
}
|
|
|
|
///Returns the set this LazySet represents. When this is called, the set is constructed in the repository.
|
|
Set set() const {
|
|
apply();
|
|
return m_set;
|
|
}
|
|
|
|
///@warning this is expensive, because the set is constructed
|
|
bool contains(const T& item) const {
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
uint index = Conversion::toIndex(item);
|
|
|
|
if( m_temporaryRemoveIndices.empty() ) {
|
|
//Simplification without creating the set
|
|
if(m_temporaryIndices.find(index) != m_temporaryIndices.end())
|
|
return true;
|
|
|
|
return m_set.contains(index);
|
|
}
|
|
|
|
return set().contains(index);
|
|
}
|
|
|
|
LazySet& operator +=(const Set& set) {
|
|
if(!m_temporaryRemoveIndices.empty())
|
|
apply();
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
m_set += set;
|
|
return *this;
|
|
}
|
|
|
|
LazySet& operator -=(const Set& set) {
|
|
if(!m_temporaryIndices.empty())
|
|
apply();
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
m_set -= set;
|
|
return *this;
|
|
}
|
|
|
|
LazySet operator +(const Set& set) const {
|
|
apply();
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
Set ret = m_set + set;
|
|
return LazySet(m_rep, m_lockBeforeAccess, ret);
|
|
}
|
|
|
|
LazySet operator -(const Set& set) const {
|
|
apply();
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
Set ret = m_set - set;
|
|
return LazySet(m_rep, m_lockBeforeAccess, ret);
|
|
}
|
|
|
|
void clear() {
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
m_set = Set();
|
|
m_temporaryIndices.clear();
|
|
m_temporaryRemoveIndices.clear();
|
|
}
|
|
|
|
ConvenientIterator<T, Conversion> iterator() const {
|
|
apply();
|
|
return ConvenientIterator<T, Conversion>(set());
|
|
}
|
|
|
|
private:
|
|
void apply() const {
|
|
if(!m_temporaryIndices.empty()) {
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
Set tempSet = m_rep->createSet(m_temporaryIndices);
|
|
m_temporaryIndices.clear();
|
|
m_set += tempSet;
|
|
}
|
|
if(!m_temporaryRemoveIndices.empty()) {
|
|
QMutexLocker l(m_lockBeforeAccess);
|
|
Set tempSet = m_rep->createSet(m_temporaryRemoveIndices);
|
|
m_temporaryRemoveIndices.clear();
|
|
m_set -= tempSet;
|
|
}
|
|
}
|
|
BasicSetRepository* m_rep;
|
|
mutable Set m_set;
|
|
QMutex* m_lockBeforeAccess;
|
|
typedef std::set<Utils::BasicSetRepository::Index> IndexList;
|
|
mutable IndexList m_temporaryIndices;
|
|
mutable IndexList m_temporaryRemoveIndices;
|
|
};
|
|
|
|
///Persistent repository that manages string-sets, also correctly increasing the string reference-counts as needed
|
|
struct KDEVPLATFORMLANGUAGE_EXPORT StringSetRepository : public Utils::BasicSetRepository {
|
|
StringSetRepository(QString name);
|
|
virtual void itemRemovedFromSets(uint index);
|
|
virtual void itemAddedToSets(uint index);
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|