1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QHASHEDSTRING_P_H
43 #define QHASHEDSTRING_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include <QtCore/qglobal.h>
57 #include <QtCore/qstring.h>
58 #include <private/qv8_p.h>
62 class QHashedStringRef;
63 class QHashedString : public QString
66 inline QHashedString();
67 inline QHashedString(const QString &string);
68 inline QHashedString(const QString &string, quint32);
69 inline QHashedString(const QHashedString &string);
71 inline QHashedString &operator=(const QHashedString &string);
72 inline bool operator==(const QHashedString &string) const;
73 inline bool operator==(const QHashedStringRef &string) const;
75 inline quint32 hash() const;
76 inline quint32 existingHash() const;
78 static inline bool isUpper(const QChar &);
80 friend class QHashedStringRef;
82 void computeHash() const;
83 mutable quint32 m_hash;
89 inline QHashedV8String();
90 explicit inline QHashedV8String(v8::Handle<v8::String>);
91 inline QHashedV8String(const QHashedV8String &string);
92 inline QHashedV8String &operator=(const QHashedV8String &other);
94 inline bool operator==(const QHashedV8String &string);
96 inline quint32 hash() const;
97 inline int length() const;
98 inline quint32 symbolId() const;
100 inline v8::Handle<v8::String> string() const;
103 v8::String::CompleteHashData m_hash;
104 v8::Handle<v8::String> m_string;
107 class QHashedStringRef
110 inline QHashedStringRef();
111 inline QHashedStringRef(const QString &);
112 inline QHashedStringRef(const QChar *, int);
113 inline QHashedStringRef(const QChar *, int, quint32);
114 inline QHashedStringRef(const QHashedString &);
115 inline QHashedStringRef(const QHashedStringRef &);
117 inline bool operator==(const QHashedString &string) const;
118 inline bool operator==(const QHashedStringRef &string) const;
120 inline quint32 hash() const;
122 inline const QChar *constData() const;
123 inline int length() const;
124 inline bool startsWithUpper() const;
127 friend class QHashedString;
129 void computeHash() const;
133 mutable quint32 m_hash;
136 class QHashedCStringRef
139 inline QHashedCStringRef();
140 inline QHashedCStringRef(const char *, int);
141 inline QHashedCStringRef(const char *, int, quint32);
142 inline QHashedCStringRef(const QHashedCStringRef &);
144 inline quint32 hash() const;
146 inline const char *constData() const;
147 inline int length() const;
149 void computeHash() const;
153 mutable quint32 m_hash;
156 class QStringHashData;
157 class QStringHashNode
161 : nlist(0), next(0), length(0), hash(0), pooled(0), ckey(0), symbolId()
165 QStringHashNode(const QHashedString &key)
166 : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(0), key(key), symbolId(0) {
169 QStringHashNode(const QHashedCStringRef &key)
170 : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(key.constData()), symbolId(0) {
173 QStringHashNode(const QStringHashNode &o)
174 : nlist(0), next(0), length(o.length), hash(o.hash), pooled(0), ckey(o.ckey), key(o.key), symbolId(o.symbolId) {
177 QStringHashNode *nlist;
178 QStringHashNode *next;
188 inline bool equals(v8::Handle<v8::String> string) {
189 return ckey?string->Equals((char*)ckey, length):
190 string->Equals((uint16_t*)key.constData(), length);
193 inline bool symbolEquals(const QHashedV8String &string) {
194 Q_ASSERT(string.symbolId() != 0);
195 return length == string.length() && hash == string.hash() &&
196 (string.symbolId() == symbolId || equals(string.string()));
199 inline bool equals(const QHashedV8String &string) {
200 return length == string.length() && hash == string.hash() &&
201 equals(string.string());
204 inline bool equals(const QHashedStringRef &string) {
205 return length == string.length() &&
206 hash == string.hash() &&
207 ckey?(cstrCompare(string.constData(), ckey, length)):
208 (0 == ::memcmp(string.constData(), key.constData(), length * sizeof(QChar)));
211 inline bool equals(const QHashedCStringRef &string) {
212 return length == string.length() &&
213 hash == string.hash() &&
214 ckey?(0 == ::memcmp(string.constData(), ckey, length)):
215 (cstrCompare(key.constData(), string.constData(), length));
219 static inline bool cstrCompare(const QChar *lhsChar, const char *rhs, int length) {
220 Q_ASSERT(lhsChar && rhs);
221 const uint16_t *lhs = (const uint16_t*)lhsChar;
223 if (*lhs++ != *rhs++) return false;
228 struct QStringHashData
232 : nodes(0), buckets(0), numBuckets(0), size(0), numBits(0) {}
234 QStringHashNode *nodes;
235 QStringHashNode **buckets;
247 struct Node : public QStringHashNode {
248 Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
249 Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
250 Node(const Node &o) : QStringHashNode(o), value(o.value) {}
254 struct ReservedNodePool
256 ReservedNodePool() : count(0), used(0), nodes(0) {}
257 ~ReservedNodePool() { delete [] nodes; }
263 QStringHashData data;
264 ReservedNodePool *nodePool;
266 inline Node *findNode(const QHashedStringRef &) const;
267 inline Node *findNode(const QHashedCStringRef &) const;
268 inline Node *findNode(const QHashedV8String &) const;
269 inline Node *findSymbolNode(const QHashedV8String &) const;
270 inline Node *createNode(const QHashedString &, const T &);
271 inline Node *createNode(const QHashedCStringRef &, const T &);
273 inline Node *takeNode(const QHashedString &key, const T &value);
274 inline Node *takeNode(const QHashedCStringRef &key, const T &value);
275 inline Node *takeNode(const Node &o);
277 inline void copy(const QStringHash<T> &);
279 inline QStringHash();
280 inline QStringHash(const QStringHash &);
281 inline ~QStringHash();
283 QStringHash &operator=(const QStringHash<T> &);
285 void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
287 inline bool isEmpty() const;
289 inline int count() const;
291 inline void insert(const QString &, const T &);
292 inline void insert(const QHashedString &, const T &);
293 inline void insert(const QHashedStringRef &, const T &);
294 inline void insert(const QHashedCStringRef &, const T &);
296 inline T *value(const QString &) const;
297 inline T *value(const QHashedString &) const;
298 inline T *value(const QHashedStringRef &) const;
299 inline T *value(const QHashedV8String &) const;
300 inline T *value(const QHashedCStringRef &) const;
302 inline bool contains(const QString &) const;
303 inline bool contains(const QHashedString &) const;
304 inline bool contains(const QHashedStringRef &) const;
305 inline bool contains(const QHashedCStringRef &) const;
307 T &operator[](const QString &);
308 T &operator[](const QHashedString &);
309 T &operator[](const QHashedStringRef &);
310 T &operator[](const QHashedCStringRef &);
312 class ConstIterator {
314 ConstIterator() : n(0) {}
315 ConstIterator(Node *n) : n(n) {}
317 ConstIterator &operator++() { n = (Node *)n->nlist; return *this; }
318 bool operator==(const ConstIterator &o) const { return n == o.n; }
319 bool operator!=(const ConstIterator &o) const { return n != o.n; }
321 QHashedString key() const {
323 return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash);
325 return QHashedString(n->key, n->hash);
328 const T &value() const { return n->value; }
329 const T &operator*() const { return n->value; }
334 ConstIterator begin() const { return ConstIterator((Node *)data.nodes); }
335 ConstIterator end() const { return ConstIterator(); }
337 inline void reserve(int);
341 QStringHash<T>::QStringHash()
347 QStringHash<T>::QStringHash(const QStringHash<T> &other)
348 : data(other.data), nodePool(0)
350 reserve(other.count());
355 QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
363 reserve(other.count());
370 void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
375 reserve(other.count() + additionalReserve);
380 QStringHash<T>::~QStringHash()
386 void QStringHash<T>::clear()
388 // If all the nodes were allocated from the node pool, we
389 // don't need to clean them individually
390 if (!nodePool || data.size != nodePool->used) {
391 QStringHashNode *n = data.nodes;
395 if (!o->pooled) delete o;
398 if (nodePool) delete nodePool;
399 delete [] data.buckets;
401 data = QStringHashData();
406 bool QStringHash<T>::isEmpty() const
408 return data.nodes == 0;
412 int QStringHash<T>::count() const
418 typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedString &key, const T &value)
420 if (nodePool && nodePool->used != nodePool->count) {
421 Node *rv = nodePool->nodes + nodePool->used++;
422 rv->length = key.length();
423 rv->hash = key.hash();
429 return new Node(key, value);
434 typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedCStringRef &key, const T &value)
436 if (nodePool && nodePool->used != nodePool->count) {
437 Node *rv = nodePool->nodes + nodePool->used++;
438 rv->length = key.length();
439 rv->hash = key.hash();
440 rv->ckey = key.constData();
445 return new Node(key, value);
450 typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
452 if (nodePool && nodePool->used != nodePool->count) {
453 Node *rv = nodePool->nodes + nodePool->used++;
454 rv->length = o.length;
459 rv->symbolId = o.symbolId;
468 void QStringHash<T>::copy(const QStringHash<T> &other)
473 QStringHashNode *n = other.data.nodes;
476 Node *mynode = takeNode(*o);
477 mynode->nlist = data.nodes;
486 typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
488 if (data.size == data.numBuckets)
491 Node *n = takeNode(key, value);
492 n->nlist = data.nodes;
495 int bucket = key.hash() % data.numBuckets;
496 n->next = data.buckets[bucket];
497 data.buckets[bucket] = n;
505 typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedCStringRef &key, const T &value)
507 if (data.size == data.numBuckets)
510 Node *n = takeNode(key, value);
511 n->nlist = data.nodes;
514 int bucket = key.hash() % data.numBuckets;
515 n->next = data.buckets[bucket];
516 data.buckets[bucket] = n;
524 void QStringHash<T>::insert(const QString &key, const T &value)
526 QHashedStringRef ch(key);
527 Node *n = findNode(key);
528 if (n) n->value = value;
529 else createNode(QHashedString(key, ch.hash()), value);
533 void QStringHash<T>::insert(const QHashedString &key, const T &value)
535 Node *n = findNode(key);
536 if (n) n->value = value;
537 else createNode(key, value);
541 void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
543 Node *n = findNode(key);
544 if (n) n->value = value;
545 else createNode(key, value);
549 void QStringHash<T>::insert(const QHashedCStringRef &key, const T &value)
551 Node *n = findNode(key);
552 if (n) n->value = value;
553 else createNode(key, value);
557 typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
559 QStringHashNode *node = 0;
560 if (data.numBuckets) {
561 node = data.buckets[string.hash() % data.numBuckets];
562 while (node && !node->equals(string))
570 typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedCStringRef &string) const
572 QStringHashNode *node = 0;
573 if (data.numBuckets) {
574 node = data.buckets[string.hash() % data.numBuckets];
575 while (node && !node->equals(string))
583 typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const
585 QStringHashNode *node = 0;
586 if (data.numBuckets) {
587 quint32 hash = string.hash();
588 node = data.buckets[hash % data.numBuckets];
589 while (node && !node->equals(string))
597 typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const
599 Q_ASSERT(string.symbolId() != 0);
601 QStringHashNode *node = 0;
602 if (data.numBuckets) {
603 quint32 hash = string.hash();
604 node = data.buckets[hash % data.numBuckets];
605 while (node && !node->symbolEquals(string))
609 node->symbolId = string.symbolId();
616 T *QStringHash<T>::value(const QString &key) const
618 Node *n = findNode(key);
619 return n?&n->value:0;
623 T *QStringHash<T>::value(const QHashedString &key) const
625 Node *n = findNode(key);
626 return n?&n->value:0;
630 T *QStringHash<T>::value(const QHashedStringRef &key) const
632 Node *n = findNode(key);
633 return n?&n->value:0;
637 T *QStringHash<T>::value(const QHashedCStringRef &key) const
639 Node *n = findNode(key);
640 return n?&n->value:0;
644 T *QStringHash<T>::value(const QHashedV8String &string) const
646 Node *n = string.symbolId()?findSymbolNode(string):findNode(string);
647 return n?&n->value:0;
651 bool QStringHash<T>::contains(const QString &s) const
653 return 0 != value(s);
657 bool QStringHash<T>::contains(const QHashedString &s) const
659 return 0 != value(s);
663 bool QStringHash<T>::contains(const QHashedStringRef &s) const
665 return 0 != value(s);
669 bool QStringHash<T>::contains(const QHashedCStringRef &s) const
671 return 0 != value(s);
675 T &QStringHash<T>::operator[](const QString &key)
677 QHashedStringRef cs(key);
678 Node *n = findNode(cs);
679 if (n) return n->value;
680 else return createNode(QHashedString(key, cs.hash()), T())->value;
684 T &QStringHash<T>::operator[](const QHashedString &key)
686 Node *n = findNode(key);
687 if (n) return n->value;
688 else return createNode(key, T())->value;
692 T &QStringHash<T>::operator[](const QHashedStringRef &key)
694 Node *n = findNode(key);
695 if (n) return n->value;
696 else return createNode(key, T())->value;
700 T &QStringHash<T>::operator[](const QHashedCStringRef &key)
702 Node *n = findNode(key);
703 if (n) return n->value;
704 else return createNode(key, T())->value;
708 void QStringHash<T>::reserve(int n)
710 if (nodePool || 0 == n)
712 nodePool = new ReservedNodePool;
715 nodePool->nodes = new Node[n];
718 inline uint qHash(const QHashedString &string)
720 return uint(string.hash());
723 inline uint qHash(const QHashedStringRef &string)
725 return uint(string.hash());
728 QHashedString::QHashedString()
729 : QString(), m_hash(0)
733 QHashedString::QHashedString(const QString &string)
734 : QString(string), m_hash(0)
738 QHashedString::QHashedString(const QString &string, quint32 hash)
739 : QString(string), m_hash(hash)
743 QHashedString::QHashedString(const QHashedString &string)
744 : QString(string), m_hash(string.m_hash)
748 QHashedString &QHashedString::operator=(const QHashedString &string)
750 static_cast<QString &>(*this) = string;
751 m_hash = string.m_hash;
755 bool QHashedString::operator==(const QHashedString &string) const
757 return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
758 static_cast<const QString &>(*this) == static_cast<const QString &>(string);
761 bool QHashedString::operator==(const QHashedStringRef &string) const
763 return length() == string.m_length &&
764 (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
765 0 == ::memcmp(constData(), string.m_data, string.m_length * sizeof(QChar));
768 quint32 QHashedString::hash() const
770 if (!m_hash) computeHash();
774 quint32 QHashedString::existingHash() const
779 bool QHashedString::isUpper(const QChar &qc)
781 ushort c = qc.unicode();
782 // Optimize for _, a-z and A-Z.
783 return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
784 ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
787 QHashedV8String::QHashedV8String()
791 QHashedV8String::QHashedV8String(v8::Handle<v8::String> string)
792 : m_hash(string->CompleteHash()), m_string(string)
794 Q_ASSERT(!m_string.IsEmpty());
797 QHashedV8String::QHashedV8String(const QHashedV8String &string)
798 : m_hash(string.m_hash), m_string(string.m_string)
802 QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other)
804 m_hash = other.m_hash;
805 m_string = other.m_string;
809 bool QHashedV8String::operator==(const QHashedV8String &string)
811 return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length &&
812 m_string.IsEmpty() == m_string.IsEmpty() &&
813 (m_string.IsEmpty() || m_string->StrictEquals(string.m_string));
816 quint32 QHashedV8String::hash() const
821 int QHashedV8String::length() const
823 return m_hash.length;
826 quint32 QHashedV8String::symbolId() const
828 return m_hash.symbol_id;
831 v8::Handle<v8::String> QHashedV8String::string() const
836 QHashedStringRef::QHashedStringRef()
837 : m_data(0), m_length(0), m_hash(0)
841 QHashedStringRef::QHashedStringRef(const QString &str)
842 : m_data(str.constData()), m_length(str.length()), m_hash(0)
846 QHashedStringRef::QHashedStringRef(const QChar *data, int length)
847 : m_data(data), m_length(length), m_hash(0)
851 QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
852 : m_data(data), m_length(length), m_hash(hash)
856 QHashedStringRef::QHashedStringRef(const QHashedString &string)
857 : m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
861 QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
862 : m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
866 bool QHashedStringRef::operator==(const QHashedString &string) const
868 return m_length == string.length() &&
869 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
870 0 == ::memcmp(string.constData(), m_data, m_length * sizeof(QChar));
873 bool QHashedStringRef::operator==(const QHashedStringRef &string) const
875 return m_length == string.m_length &&
876 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
877 0 == ::memcmp(string.m_data, m_data, m_length * sizeof(QChar));
880 const QChar *QHashedStringRef::constData() const
885 int QHashedStringRef::length() const
890 bool QHashedStringRef::startsWithUpper() const
892 if (m_length < 1) return false;
893 return QHashedString::isUpper(m_data[0]);
896 quint32 QHashedStringRef::hash() const
898 if (!m_hash) computeHash();
902 QHashedCStringRef::QHashedCStringRef()
903 : m_data(0), m_length(0), m_hash(0)
907 QHashedCStringRef::QHashedCStringRef(const char *data, int length)
908 : m_data(data), m_length(length), m_hash(0)
912 QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash)
913 : m_data(data), m_length(length), m_hash(hash)
917 QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o)
918 : m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash)
922 quint32 QHashedCStringRef::hash() const
924 if (!m_hash) computeHash();
928 const char *QHashedCStringRef::constData() const
933 int QHashedCStringRef::length() const
941 #endif // QHASHEDSTRING_P_H