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 quint32 length() const;
124 inline bool startsWithUpper() const;
127 friend class QHashedString;
129 void computeHash() const;
133 mutable quint32 m_hash;
136 class QStringHashData;
137 class QStringHashNode
140 QStringHashNode(const QHashedString &key)
141 : nlist(0), next(0), key(key), symbolId(0) {
144 QStringHashNode *nlist;
145 QStringHashNode *next;
149 inline bool equals(v8::Handle<v8::String> string) {
150 return string->Equals((uint16_t*)key.constData(), key.length());
154 struct QStringHashData
158 : nodes(0), buckets(0), numBuckets(0), size(0), numBits(0) {}
160 QStringHashNode *nodes;
161 QStringHashNode **buckets;
173 struct Node : public QStringHashNode {
174 Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
178 QStringHashData data;
180 inline Node *findNode(const QHashedStringRef &) const;
181 inline Node *findNode(const QHashedV8String &) const;
182 inline Node *findSymbolNode(const QHashedV8String &) const;
183 Node *createNode(const QHashedString &, const T &);
186 inline QStringHash();
187 inline QStringHash(const QStringHash &);
188 inline ~QStringHash();
190 QStringHash &operator=(const QStringHash<T> &);
192 inline bool isEmpty() const;
194 inline int count() const;
196 inline void insert(const QString &, const T &);
197 inline void insert(const QHashedString &, const T &);
198 inline void insert(const QHashedStringRef &, const T &);
200 inline T *value(const QString &) const;
201 inline T *value(const QHashedString &) const;
202 inline T *value(const QHashedStringRef &) const;
203 inline T *value(const QHashedV8String &) const;
205 inline bool contains(const QString &) const;
206 inline bool contains(const QHashedString &) const;
207 inline bool contains(const QHashedStringRef &) const;
209 T &operator[](const QString &);
210 T &operator[](const QHashedString &);
211 T &operator[](const QHashedStringRef &);
213 class ConstIterator {
215 ConstIterator() : n(0) {}
216 ConstIterator(Node *n) : n(n) {}
218 ConstIterator &operator++() { n = (Node *)n->nlist; return *this; }
219 bool operator==(const ConstIterator &o) const { return n == o.n; }
220 bool operator!=(const ConstIterator &o) const { return n != o.n; }
222 const QHashedString &key() const { return n->key; }
223 const T &value() const { return n->value; }
224 const T &operator*() const { return n->value; }
229 ConstIterator begin() const { return ConstIterator((Node *)data.nodes); }
230 ConstIterator end() const { return ConstIterator(); }
234 QStringHash<T>::QStringHash()
239 QStringHash<T>::QStringHash(const QStringHash<T> &other)
245 QStringHashNode *n = other.data.nodes;
248 Node *mynode = new Node(o->key, o->value);
249 mynode->nlist = data.nodes;
258 QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
268 QStringHashNode *n = other.data.nodes;
271 Node *mynode = new Node(o->key, o->value);
272 mynode->nlist = data.nodes;
283 QStringHash<T>::~QStringHash()
289 void QStringHash<T>::clear()
291 QStringHashNode *n = data.nodes;
298 delete [] data.buckets;
300 data = QStringHashData();
304 bool QStringHash<T>::isEmpty() const
306 return data.nodes == 0;
310 int QStringHash<T>::count() const
316 typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
318 if (data.size == data.numBuckets)
321 Node *n = new Node(key, value);
322 n->nlist = data.nodes;
325 int bucket = key.hash() % data.numBuckets;
326 n->next = data.buckets[bucket];
327 data.buckets[bucket] = n;
335 void QStringHash<T>::insert(const QString &key, const T &value)
337 QHashedStringRef ch(key);
338 Node *n = findNode(key);
339 if (n) n->value = value;
340 else createNode(QHashedString(key, ch.hash()), value);
344 void QStringHash<T>::insert(const QHashedString &key, const T &value)
346 Node *n = findNode(key);
347 if (n) n->value = value;
348 else createNode(key, value);
352 void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
354 Node *n = findNode(key);
355 if (n) n->value = value;
356 else createNode(key, value);
360 typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
362 QStringHashNode *node = 0;
363 if (data.numBuckets) {
364 node = data.buckets[string.hash() % data.numBuckets];
365 while (node && !(node->key == string))
373 typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const
375 QStringHashNode *node = 0;
376 if (data.numBuckets) {
377 quint32 hash = string.hash();
378 node = data.buckets[hash % data.numBuckets];
379 int length = string.length();
380 while (node && (length != node->key.length() || hash != node->key.hash() || !node->equals(string.string())))
388 typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const
390 Q_ASSERT(string.symbolId() != 0);
392 QStringHashNode *node = 0;
393 if (data.numBuckets) {
394 quint32 hash = string.hash();
395 quint32 symbolId = string.symbolId();
396 node = data.buckets[hash % data.numBuckets];
397 int length = string.length();
398 while (node && (length != node->key.length() || hash != node->key.hash() ||
399 !(node->symbolId == symbolId || node->equals(string.string()))))
402 node->symbolId = symbolId;
409 T *QStringHash<T>::value(const QString &key) const
411 Node *n = findNode(key);
412 return n?&n->value:0;
416 T *QStringHash<T>::value(const QHashedString &key) const
418 Node *n = findNode(key);
419 return n?&n->value:0;
423 T *QStringHash<T>::value(const QHashedStringRef &key) const
425 Node *n = findNode(key);
426 return n?&n->value:0;
430 T *QStringHash<T>::value(const QHashedV8String &string) const
432 Node *n = string.symbolId()?findSymbolNode(string):findNode(string);
433 return n?&n->value:0;
437 bool QStringHash<T>::contains(const QString &s) const
439 return 0 != value(s);
443 bool QStringHash<T>::contains(const QHashedString &s) const
445 return 0 != value(s);
448 bool QStringHash<T>::contains(const QHashedStringRef &s) const
450 return 0 != value(s);
454 T &QStringHash<T>::operator[](const QString &key)
456 QHashedStringRef cs(key);
457 Node *n = findNode(cs);
458 if (n) return n->value;
459 else return createNode(QHashedString(key, cs.hash()), T())->value;
463 T &QStringHash<T>::operator[](const QHashedString &key)
465 Node *n = findNode(key);
466 if (n) return n->value;
467 else return createNode(key, T())->value;
471 T &QStringHash<T>::operator[](const QHashedStringRef &key)
473 Node *n = findNode(key);
474 if (n) return n->value;
475 else return createNode(key, T())->value;
478 inline uint qHash(const QHashedString &string)
480 return uint(string.hash());
483 inline uint qHash(const QHashedStringRef &string)
485 return uint(string.hash());
488 QHashedString::QHashedString()
489 : QString(), m_hash(0)
493 QHashedString::QHashedString(const QString &string)
494 : QString(string), m_hash(0)
498 QHashedString::QHashedString(const QString &string, quint32 hash)
499 : QString(string), m_hash(hash)
503 QHashedString::QHashedString(const QHashedString &string)
504 : QString(string), m_hash(string.m_hash)
508 QHashedString &QHashedString::operator=(const QHashedString &string)
510 static_cast<QString &>(*this) = string;
511 m_hash = string.m_hash;
515 bool QHashedString::operator==(const QHashedString &string) const
517 return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
518 static_cast<const QString &>(*this) == static_cast<const QString &>(string);
521 bool QHashedString::operator==(const QHashedStringRef &string) const
523 return (uint)length() == string.m_length &&
524 (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
525 0 == ::memcmp(constData(), string.m_data, string.m_length * sizeof(QChar));
528 quint32 QHashedString::hash() const
530 if (!m_hash) computeHash();
534 quint32 QHashedString::existingHash() const
539 bool QHashedString::isUpper(const QChar &qc)
541 ushort c = qc.unicode();
542 // Optimize for _, a-z and A-Z.
543 return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
544 ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
547 QHashedV8String::QHashedV8String()
551 QHashedV8String::QHashedV8String(v8::Handle<v8::String> string)
552 : m_hash(string->CompleteHash()), m_string(string)
554 Q_ASSERT(!m_string.IsEmpty());
557 QHashedV8String::QHashedV8String(const QHashedV8String &string)
558 : m_hash(string.m_hash), m_string(string.m_string)
562 QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other)
564 m_hash = other.m_hash;
565 m_string = other.m_string;
569 bool QHashedV8String::operator==(const QHashedV8String &string)
571 return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length &&
572 m_string.IsEmpty() == m_string.IsEmpty() &&
573 (m_string.IsEmpty() || m_string->StrictEquals(string.m_string));
576 quint32 QHashedV8String::hash() const
581 int QHashedV8String::length() const
583 return m_hash.length;
586 quint32 QHashedV8String::symbolId() const
588 return m_hash.symbol_id;
591 v8::Handle<v8::String> QHashedV8String::string() const
596 QHashedStringRef::QHashedStringRef()
597 : m_data(0), m_length(0), m_hash(0)
601 QHashedStringRef::QHashedStringRef(const QString &str)
602 : m_data(str.constData()), m_length(str.length()), m_hash(0)
606 QHashedStringRef::QHashedStringRef(const QChar *data, int length)
607 : m_data(data), m_length(length), m_hash(0)
611 QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
612 : m_data(data), m_length(length), m_hash(hash)
616 QHashedStringRef::QHashedStringRef(const QHashedString &string)
617 : m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
621 QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
622 : m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
626 bool QHashedStringRef::operator==(const QHashedString &string) const
628 return m_length == (uint)string.length() &&
629 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
630 0 == ::memcmp(string.constData(), m_data, m_length * sizeof(QChar));
633 bool QHashedStringRef::operator==(const QHashedStringRef &string) const
635 return m_length == string.m_length &&
636 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
637 0 == ::memcmp(string.m_data, m_data, m_length * sizeof(QChar));
640 const QChar *QHashedStringRef::constData() const
645 quint32 QHashedStringRef::length() const
650 bool QHashedStringRef::startsWithUpper() const
652 if (m_length < 1) return false;
653 return QHashedString::isUpper(m_data[0]);
656 quint32 QHashedStringRef::hash() const
658 if (!m_hash) computeHash();
664 #endif // QHASHEDSTRING_P_H