Files
SingularityViewer/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h
2012-09-08 02:03:07 -04:00

248 lines
7.2 KiB
C++

/* Copyright (c) 2006-2010, Linden Research, Inc.
*
* LLQtWebKit Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in GPL-license.txt in this distribution, or online at
* http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
*/
#ifndef TRIE_H
#define TRIE_H
//#define TRIE_DEBUG
#include <qstringlist.h>
#if defined(TRIE_DEBUG)
#include <qdebug.h>
#endif
/*
A Trie tree (prefix tree) where the lookup takes m in the worst case.
The key is stored in *reverse* order
Example:
Keys: x,a y,a
Trie:
a
| \
x y
*/
template<class T>
class Trie {
public:
Trie();
~Trie();
void clear();
void insert(const QStringList &key, const T &value);
bool remove(const QStringList &key, const T &value);
QList<T> find(const QStringList &key) const;
QList<T> all() const;
inline bool contains(const QStringList &key) const;
inline bool isEmpty() const { return children.isEmpty() && values.isEmpty(); }
private:
const Trie<T>* walkTo(const QStringList &key) const;
Trie<T>* walkTo(const QStringList &key, bool create = false);
template<class T1> friend QDataStream &operator<<(QDataStream &, const Trie<T1>&);
template<class T1> friend QDataStream &operator>>(QDataStream &, Trie<T1>&);
QList<T> values;
QStringList childrenKeys;
QList<Trie<T> > children;
};
template<class T>
Trie<T>::Trie() {
}
template<class T>
Trie<T>::~Trie() {
}
template<class T>
void Trie<T>::clear() {
#if defined(TRIE_DEBUG)
qDebug() << "Trie::" << __FUNCTION__;
#endif
values.clear();
childrenKeys.clear();
children.clear();
}
template<class T>
bool Trie<T>::contains(const QStringList &key) const {
return walkTo(key);
}
template<class T>
void Trie<T>::insert(const QStringList &key, const T &value) {
#if defined(TRIE_DEBUG)
qDebug() << "Trie::" << __FUNCTION__ << key << value;
#endif
Trie<T> *node = walkTo(key, true);
if (node)
node->values.append(value);
}
template<class T>
bool Trie<T>::remove(const QStringList &key, const T &value) {
#if defined(TRIE_DEBUG)
qDebug() << "Trie::" << __FUNCTION__ << key << value;
#endif
Trie<T> *node = walkTo(key, true);
if (node) {
bool removed = node->values.removeOne(value);
if (!removed)
return false;
// A faster implementation of removing nodes up the tree
// can be created if profile shows this to be slow
QStringList subKey = key;
while (node->values.isEmpty()
&& node->children.isEmpty()
&& !subKey.isEmpty()) {
QString currentLevelKey = subKey.first();
QStringList parentKey = subKey.mid(1);
Trie<T> *parent = walkTo(parentKey, false);
Q_ASSERT(parent);
QStringList::iterator iterator;
iterator = qBinaryFind(parent->childrenKeys.begin(),
parent->childrenKeys.end(),
currentLevelKey);
Q_ASSERT(iterator != parent->childrenKeys.end());
int index = iterator - parent->childrenKeys.begin();
parent->children.removeAt(index);
parent->childrenKeys.removeAt(index);
node = parent;
subKey = parentKey;
}
return removed;
}
return false;
}
template<class T>
QList<T> Trie<T>::find(const QStringList &key) const {
#if defined(TRIE_DEBUG)
qDebug() << "Trie::" << __FUNCTION__ << key;
#endif
const Trie<T> *node = walkTo(key);
if (node)
return node->values;
return QList<T>();
}
template<class T>
QList<T> Trie<T>::all() const {
#if defined(TRIE_DEBUG)
qDebug() << "Trie::" << __FUNCTION__;
#endif
QList<T> all = values;
for (int i = 0; i < children.count(); ++i)
all += children[i].all();
return all;
}
template<class T>
QDataStream &operator<<(QDataStream &out, const Trie<T>&trie) {
out << trie.values;
out << trie.childrenKeys;
out << trie.children;
Q_ASSERT(trie.childrenKeys.count() == trie.children.count());
return out;
}
template<class T>
QDataStream &operator>>(QDataStream &in, Trie<T> &trie) {
trie.clear();
if (in.status() != QDataStream::Ok)
return in;
in >> trie.values;
in >> trie.childrenKeys;
in >> trie.children;
//Q_ASSERT(trie.childrenKeys.count() == trie.children.count());
if (trie.childrenKeys.count() != trie.children.count())
in.setStatus(QDataStream::ReadCorruptData);
return in;
}
// Very fast const walk
template<class T>
const Trie<T>* Trie<T>::walkTo(const QStringList &key) const {
const Trie<T> *node = this;
QStringList::const_iterator childIterator;
QStringList::const_iterator begin, end;
int depth = key.count() - 1;
while (depth >= 0) {
const QString currentLevelKey = key.at(depth--);
begin = node->childrenKeys.constBegin();
end = node->childrenKeys.constEnd();
childIterator = qBinaryFind(begin, end, currentLevelKey);
if (childIterator == end)
return 0;
node = &node->children.at(childIterator - begin);
}
return node;
}
template<class T>
Trie<T>* Trie<T>::walkTo(const QStringList &key, bool create) {
QStringList::iterator iterator;
Trie<T> *node = this;
QStringList::iterator begin, end;
int depth = key.count() - 1;
while (depth >= 0) {
const QString currentLevelKey = key.at(depth--);
begin = node->childrenKeys.begin();
end = node->childrenKeys.end();
iterator = qBinaryFind(begin, end, currentLevelKey);
#if defined(TRIE_DEBUG)
qDebug() << "\t" << node << key << currentLevelKey << node->childrenKeys;
#endif
int index = -1;
if (iterator == end) {
if (!create)
return 0;
iterator = qLowerBound(begin,
end,
currentLevelKey);
index = iterator - begin;
node->childrenKeys.insert(iterator, currentLevelKey);
node->children.insert(index, Trie<T>());
} else {
index = iterator - begin;
}
Q_ASSERT(index >= 0 && index < node->children.count());
node = &node->children[index];
}
return node;
}
#endif