2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
30 #include <QtCore/QHash>
31 #include <QtCore/QList>
32 #include <QtCore/QSet>
34 template<class T
> class MultiMapPtrList
;
36 template<class K
, class T
>
40 typedef QHash
<K
*, Set
*> Map
;
41 typedef MultiMapPtrList
<T
*> List
;
49 void insert(K
* key
, T
* element
)
51 Set
*set
= map
.value(key
);
56 if (!set
->contains(element
))
59 void remove(K
* key
, T
* element
)
61 Set
*set
= map
.value(key
);
71 Set
*set
= map
.value(key
);
78 return map
.value(key
);
84 static inline unsigned int stupidHash(void* ptr
)
86 unsigned long val
= (unsigned long)ptr
;
87 // remove alignment and multiply by a prime unlikely to be a factor of size
88 val
= (val
>> 4) * 1237;
92 #define START_PTRLIST_SIZE 4
93 #define MAX_PTRLIST_SIZE 27
97 PtrListEntry(unsigned int log_size
) : count(0), log_size(log_size
), search(log_size
), next(0) {
98 // entry = new T* [size];
99 assert(log_size
< MAX_PTRLIST_SIZE
);
100 entry
= (void**)calloc ((1<<log_size
), sizeof(void*));
106 bool insert(void* e
) {
107 unsigned int t_size
= size();
108 if (count
== t_size
) return false;
109 unsigned int hash
= stupidHash(e
);
110 void** firstFree
= 0;
111 // Only let elements be placed 'search' spots from their hash
112 for(unsigned int j
=0; j
<search
; j
++) {
113 unsigned int i
= (hash
+ j
) & (t_size
-1); // modulo size
114 // We need check to all hashes in 'search' to garuantee uniqueness
117 firstFree
= entry
+ i
;
127 // We had more than 'search' collisions
128 if (count
< (t_size
/3)*2) {
129 // only 2/3 full => increase search
130 unsigned int s
= search
*2;
131 if (s
>= t_size
) s
= t_size
;
137 // Insert another smaller set into this one
138 // Is only garuantied to succede when this PtrList is new
139 void insert(PtrListEntry
* listEntry
) {
140 assert(size() >= listEntry
->count
* 2);
141 unsigned int old_size
= 1U << listEntry
->log_size
;
142 for(unsigned int i
= 0; i
< old_size
; i
++) {
144 void *e
= listEntry
->entry
[i
];
145 if (e
) s
= insert(e
);
149 bool remove(void* e
) {
150 if (count
== 0) return false;
151 unsigned int size
= (1U<<log_size
);
152 unsigned int hash
= stupidHash(e
);
153 // Elements are at most placed 'search' spots from their hash
154 for(unsigned int j
=0; j
<search
; j
++) {
155 unsigned int i
= (hash
+ j
) & (size
-1); // modulo size
164 bool contains(void* e
) {
165 if (count
== 0) return false;
166 unsigned int t_size
= size();
167 unsigned int hash
= stupidHash(e
);
168 // Elements are at most placed 'search' spots from their hash
169 for(unsigned int j
=0; j
<search
; j
++) {
170 unsigned int i
= (hash
+ j
) & (t_size
-1); // modulo size
171 if (entry
[i
] == e
) return true;
175 void* at(unsigned int i
) const {
176 assert (i
< (1U<<log_size
));
179 bool isEmpty() const {
182 bool isFull() const {
183 return count
== size();
185 unsigned int size() const {
186 return (1U << log_size
);
190 const unsigned short log_size
;
191 unsigned short search
;
196 // An unsorted and unique PtrList that is implement as a linked list of hash-sets
197 // Optimized for fast insert and fast lookup
199 class MultiMapPtrList
{
201 MultiMapPtrList(unsigned int init_size
= 16) : m_first(0), m_current(0), m_pos(0) {
202 assert(init_size
> 0);
203 unsigned int s
= init_size
- 1;
204 unsigned int log_size
= 0;
209 m_first
= new PtrListEntry(log_size
);
211 MultiMapPtrList(const MultiMapPtrList
& ptrList
) : m_first(0), m_current(0), m_pos(0) {
212 unsigned int t_count
= ptrList
.count();
213 unsigned int log_size
= 0;
214 while (t_count
> 0) {
216 t_count
= t_count
>> 1;
218 // At least as large as the largest ptrListEntry in the original
219 if (t_count
< ptrList
.m_first
->log_size
) log_size
= ptrList
.m_first
->log_size
;
220 m_first
= new PtrListEntry(log_size
);
222 PtrListEntry
*t_current
= ptrList
.m_first
;
224 unsigned int t_size
= t_current
->size();
225 for(unsigned int i
=0; i
< t_size
; i
++) {
226 void* e
= t_current
->at(i
);
228 bool t
= m_first
->insert(e
);
230 // Make a new, but keep the size
231 PtrListEntry
*t_new
= new PtrListEntry(log_size
);
233 t_new
->next
= m_first
;
238 t_current
= t_current
->next
;
242 PtrListEntry
*t_next
, *t_current
= m_first
;
244 t_next
= t_current
->next
;
250 PtrListEntry
*t_last
= 0, *t_current
= m_first
;
253 if (t_current
->insert(e
)) return;
255 t_current
= t_current
->next
;
258 // Create new hash-set
259 unsigned int newsize
= m_first
->log_size
+1;
260 if (newsize
> MAX_PTRLIST_SIZE
) newsize
= MAX_PTRLIST_SIZE
;
261 t_current
= new PtrListEntry(newsize
);
262 bool t
= t_current
->insert(e
);
264 // Prepend it to the list, for insert effeciency
265 t_current
->next
= m_first
;
267 // ### rehash some of the smaller sets
270 // rehash the last in the new
271 t_current->insert(t_last);
275 PtrListEntry
*t_next
, *t_last
= 0, *t_current
= m_first
;
276 // Remove has to check every PtrEntry.
278 t_next
= t_current
->next
;
279 if (t_current
->remove(e
) && t_current
->isEmpty()) {
281 t_last
->next
= t_current
->next
;
284 assert (m_first
== t_current
);
285 m_first
= t_current
->next
;
294 bool contains(T
* e
) {
295 PtrListEntry
*t_current
= m_first
;
297 if (t_current
->contains(e
)) return true;
298 t_current
= t_current
->next
;
303 if (!m_first
) return true;
304 PtrListEntry
*t_current
= m_first
;
306 if (!t_current
->isEmpty()) return false;
307 t_current
= t_current
->next
;
311 unsigned int count() const {
312 unsigned int t_count
= 0;
313 PtrListEntry
*t_current
= m_first
;
315 t_count
+= t_current
->count
;
316 t_current
= t_current
->next
;
320 // Iterator functions:
325 if (m_current
&& !m_current
->at(m_pos
))
334 return (T
*)m_current
->at(m_pos
);
337 if (!m_current
) return (T
*)0;
339 if (m_pos
>= m_current
->size()) {
340 m_current
= m_current
->next
;
344 if (m_current
&& !m_current
->at(m_pos
))
350 PtrListEntry
*m_first
;
352 PtrListEntry
*m_current
;
356 #undef START_PTRLIST_SIZE
357 #undef MAX_PTRLIST_SIZE