source: trunk/src/corelib/tools/qhash.cpp@ 986

Last change on this file since 986 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 52.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qhash.h"
43
44#ifdef truncate
45#undef truncate
46#endif
47
48#include <qbitarray.h>
49#include <qstring.h>
50#include <stdlib.h>
51#ifdef QT_QHASH_DEBUG
52#include <qstring.h>
53#endif
54
55QT_BEGIN_NAMESPACE
56
57/*
58 These functions are based on Peter J. Weinberger's hash function
59 (from the Dragon Book). The constant 24 in the original function
60 was replaced with 23 to produce fewer collisions on input such as
61 "a", "aa", "aaa", "aaaa", ...
62*/
63
64static uint hash(const uchar *p, int n)
65{
66 uint h = 0;
67
68 while (n--) {
69 h = (h << 4) + *p++;
70 h ^= (h & 0xf0000000) >> 23;
71 h &= 0x0fffffff;
72 }
73 return h;
74}
75
76static uint hash(const QChar *p, int n)
77{
78 uint h = 0;
79
80 while (n--) {
81 h = (h << 4) + (*p++).unicode();
82 h ^= (h & 0xf0000000) >> 23;
83 h &= 0x0fffffff;
84 }
85 return h;
86}
87
88uint qHash(const QByteArray &key)
89{
90 return hash(reinterpret_cast<const uchar *>(key.constData()), key.size());
91}
92
93uint qHash(const QString &key)
94{
95 return hash(key.unicode(), key.size());
96}
97
98uint qHash(const QStringRef &key)
99{
100 return hash(key.unicode(), key.size());
101}
102
103uint qHash(const QBitArray &bitArray)
104{
105 int m = bitArray.d.size() - 1;
106 uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()), qMax(0, m));
107
108 // deal with the last 0 to 7 bits manually, because we can't trust that
109 // the padding is initialized to 0 in bitArray.d
110 int n = bitArray.size();
111 if (n & 0x7)
112 result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
113 return result;
114}
115
116/*
117 The prime_deltas array is a table of selected prime values, even
118 though it doesn't look like one. The primes we are using are 1,
119 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
120 surrounding of a power of two.
121
122 The primeForNumBits() function returns the prime associated to a
123 power of two. For example, primeForNumBits(8) returns 257.
124*/
125
126static const uchar prime_deltas[] = {
127 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
128 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
129};
130
131static inline int primeForNumBits(int numBits)
132{
133 return (1 << numBits) + prime_deltas[numBits];
134}
135
136/*
137 Returns the smallest integer n such that
138 primeForNumBits(n) >= hint.
139*/
140static int countBits(int hint)
141{
142 int numBits = 0;
143 int bits = hint;
144
145 while (bits > 1) {
146 bits >>= 1;
147 numBits++;
148 }
149
150 if (numBits >= (int)sizeof(prime_deltas)) {
151 numBits = sizeof(prime_deltas) - 1;
152 } else if (primeForNumBits(numBits) < hint) {
153 ++numBits;
154 }
155 return numBits;
156}
157
158/*
159 A QHash has initially around pow(2, MinNumBits) buckets. For
160 example, if MinNumBits is 4, it has 17 buckets.
161*/
162const int MinNumBits = 4;
163
164QHashData QHashData::shared_null = {
165 0, 0, Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, MinNumBits, 0, 0, true, false, 0
166};
167
168void *QHashData::allocateNode()
169{
170 return allocateNode(0);
171}
172
173void *QHashData::allocateNode(int nodeAlign)
174{
175 void *ptr = strictAlignment ? qMallocAligned(nodeSize, nodeAlign) : qMalloc(nodeSize);
176 Q_CHECK_PTR(ptr);
177 return ptr;
178}
179
180void QHashData::freeNode(void *node)
181{
182 if (strictAlignment)
183 qFreeAligned(node);
184 else
185 qFree(node);
186}
187
188QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize)
189{
190 return detach_helper2( node_duplicate, 0, nodeSize, 0 );
191}
192
193QHashData *QHashData::detach_helper2(void (*node_duplicate)(Node *, void *),
194 void (*node_delete)(Node *),
195 int nodeSize,
196 int nodeAlign)
197{
198 union {
199 QHashData *d;
200 Node *e;
201 };
202 d = new QHashData;
203 d->fakeNext = 0;
204 d->buckets = 0;
205 d->ref = 1;
206 d->size = size;
207 d->nodeSize = nodeSize;
208 d->userNumBits = userNumBits;
209 d->numBits = numBits;
210 d->numBuckets = numBuckets;
211 d->sharable = true;
212 d->strictAlignment = nodeAlign > 8;
213 d->reserved = 0;
214
215 if (numBuckets) {
216 QT_TRY {
217 d->buckets = new Node *[numBuckets];
218 } QT_CATCH(...) {
219 // restore a consistent state for d
220 d->numBuckets = 0;
221 // roll back
222 d->free_helper(node_delete);
223 QT_RETHROW;
224 }
225
226 Node *this_e = reinterpret_cast<Node *>(this);
227 for (int i = 0; i < numBuckets; ++i) {
228 Node **nextNode = &d->buckets[i];
229 Node *oldNode = buckets[i];
230 while (oldNode != this_e) {
231 QT_TRY {
232 Node *dup = static_cast<Node *>(allocateNode(nodeAlign));
233
234 QT_TRY {
235 node_duplicate(oldNode, dup);
236 } QT_CATCH(...) {
237 freeNode( dup );
238 QT_RETHROW;
239 }
240
241 dup->h = oldNode->h;
242 *nextNode = dup;
243 nextNode = &dup->next;
244 oldNode = oldNode->next;
245 } QT_CATCH(...) {
246 // restore a consistent state for d
247 *nextNode = e;
248 d->numBuckets = i+1;
249 // roll back
250 d->free_helper(node_delete);
251 QT_RETHROW;
252 }
253 }