Warning, file /frameworks/khtml/src/misc/multimap.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #ifndef _MultiMap_h_
0024 #define _MultiMap_h_
0025 
0026 #include <assert.h>
0027 #include <stdlib.h>
0028 
0029 #include <QHash>
0030 #include <QList>
0031 #include <QSet>
0032 
0033 template<class T> class MultiMapPtrList;
0034 
0035 template<class K, class T>
0036 class KMultiMap
0037 {
0038 public:
0039     typedef QSet<T *> Set;
0040     typedef QHash<K *, Set *> Map;
0041     typedef MultiMapPtrList<T *> List;
0042 
0043     KMultiMap() {}
0044     ~KMultiMap()
0045     {
0046         qDeleteAll(map);
0047         map.clear();
0048     }
0049 
0050     void insert(K *key, T *element)
0051     {
0052         Set *set = map.value(key);
0053         if (!set) {
0054             set = new Set();
0055             map.insert(key, set);
0056         }
0057         if (!set->contains(element)) {
0058             set->insert(element);
0059         }
0060     }
0061     void remove(K *key, T *element)
0062     {
0063         Set *set = map.value(key);
0064         if (set) {
0065             set->remove(element);
0066             if (set->isEmpty()) {
0067                 map.remove(key);
0068                 delete set;
0069             }
0070         }
0071     }
0072     void remove(K *key)
0073     {
0074         Set *set = map.value(key);
0075         if (set) {
0076             map.remove(key);
0077             delete set;
0078         }
0079     }
0080     Set *find(K *key)
0081     {
0082         return map.value(key);
0083     }
0084 private:
0085     Map map;
0086 };
0087 
0088 static inline unsigned int stupidHash(void *ptr)
0089 {
0090     unsigned long val = (unsigned long)ptr;
0091     // remove alignment and multiply by a prime unlikely to be a factor of size
0092     val = (val >> 4) * 1237;
0093     return val;
0094 }
0095 
0096 #define START_PTRLIST_SIZE 4
0097 #define MAX_PTRLIST_SIZE 27
0098 
0099 class PtrListEntry
0100 {
0101 public:
0102     PtrListEntry(unsigned int log_size) : count(0), log_size(log_size), search(log_size), next(0)
0103     {
0104 //         entry = new T* [size];
0105         assert(log_size < MAX_PTRLIST_SIZE);
0106         entry = (void **)calloc((1 << log_size), sizeof(void *));
0107     }
0108     ~PtrListEntry()
0109     {
0110 //         delete[] entry;
0111         free(entry);
0112     }
0113     bool insert(void *e)
0114     {
0115         unsigned int t_size = size();
0116         if (count == t_size) {
0117             return false;
0118         }
0119         unsigned int hash = stupidHash(e);
0120         void **firstFree = 0;
0121         // Only let elements be placed 'search' spots from their hash
0122         for (unsigned int j = 0; j < search; j++) {
0123             unsigned int i = (hash + j) & (t_size - 1); // modulo size
0124             // We need check to all hashes in 'search' to garuantee uniqueness
0125             if (entry[i] == 0) {
0126                 if (!firstFree) {
0127                     firstFree = entry + i;
0128                 }
0129             } else if (entry[i] == e) {
0130                 return true;
0131             }
0132         }
0133         if (firstFree) {
0134             *firstFree = e;
0135             count++;
0136             return true;
0137         }
0138         // We had more than 'search' collisions
0139         if (count < (t_size / 3) * 2) {
0140             // only 2/3 full => increase search
0141             unsigned int s = search * 2;
0142             if (s >= t_size) {
0143                 s = t_size;
0144             }
0145             search = s;
0146             return insert(e);
0147         }
0148         return false;
0149     }
0150     // Insert another smaller set into this one
0151     // Is only garuantied to succede when this PtrList is new
0152     void insert(PtrListEntry *listEntry)
0153     {
0154         assert(size() >= listEntry->count * 2);
0155         unsigned int old_size = 1U << listEntry->log_size;
0156         for (unsigned int i = 0; i < old_size; i++) {
0157             bool s = true;
0158             void *e = listEntry->entry[i];
0159             if (e) {
0160                 s = insert(e);
0161             }
0162             assert(s);
0163         }
0164     }
0165     bool remove(void *e)
0166     {
0167         if (count == 0) {
0168             return false;
0169         }
0170         unsigned int size = (1U << log_size);
0171         unsigned int hash = stupidHash(e);
0172         // Elements are at most placed 'search' spots from their hash
0173         for (unsigned int j = 0; j < search; j++) {
0174             unsigned int i = (hash + j) & (size - 1); // modulo size
0175             if (entry[i] == e) {
0176                 entry[i] = 0;
0177                 count--;
0178                 return true;
0179             }
0180         }
0181         return false;
0182     }
0183     bool contains(void *e)
0184     {
0185         if (count == 0) {
0186             return false;
0187         }
0188         unsigned int t_size = size();
0189         unsigned int hash = stupidHash(e);
0190         // Elements are at most placed 'search' spots from their hash
0191         for (unsigned int j = 0; j < search; j++) {
0192             unsigned int i = (hash + j) & (t_size - 1); // modulo size
0193             if (entry[i] == e) {
0194                 return true;
0195             }
0196         }
0197         return false;
0198     }
0199     void *at(unsigned int i) const
0200     {
0201         assert(i < (1U << log_size));
0202         return entry[i];
0203     }
0204     bool isEmpty() const
0205     {
0206         return count == 0;
0207     }
0208     bool isFull() const
0209     {
0210         return count == size();
0211     }
0212     unsigned int size() const
0213     {
0214         return (1U << log_size);
0215     }
0216 
0217     unsigned int count;
0218     const unsigned short log_size;
0219     unsigned short search;
0220     PtrListEntry *next;
0221     void **entry;
0222 };
0223 
0224 // An unsorted and unique PtrList that is implement as a linked list of hash-sets
0225 // Optimized for fast insert and fast lookup
0226 template<class T>
0227 class MultiMapPtrList
0228 {
0229 public:
0230     MultiMapPtrList(unsigned int init_size = 16) : m_first(0), m_current(0), m_pos(0)
0231     {
0232         assert(init_size > 0);
0233         unsigned int s = init_size - 1;
0234         unsigned int log_size = 0;
0235         while (s > 0) {
0236             log_size++;
0237             s = s >> 1;
0238         }
0239         m_first = new PtrListEntry(log_size);
0240     }
0241     MultiMapPtrList(const MultiMapPtrList &ptrList) : m_first(0), m_current(0), m_pos(0)
0242     {
0243         unsigned int t_count = ptrList.count();
0244         unsigned int log_size = 0;
0245         while (t_count > 0) {
0246             log_size++;
0247             t_count = t_count >> 1;
0248         }
0249         // At least as large as the largest ptrListEntry in the original
0250         if (t_count < ptrList.m_first->log_size) {
0251             log_size = ptrList.m_first->log_size;
0252         }
0253         m_first = new PtrListEntry(log_size);
0254 
0255         PtrListEntry *t_current = ptrList.m_first;
0256         while (t_current) {
0257             unsigned int t_size = t_current->size();
0258             for (unsigned int i = 0; i < t_size; i++) {
0259                 void *e = t_current->at(i);
0260                 if (e != 0) {
0261                     bool t = m_first->insert(e);
0262                     if (!t) {
0263                         // Make a new, but keep the size
0264                         PtrListEntry *t_new = new PtrListEntry(log_size);
0265                         t_new->insert(e);
0266                         t_new->next = m_first;
0267                         m_first = t_new;
0268                     }
0269                 }
0270             }
0271             t_current = t_current->next;
0272         }
0273     }
0274     ~MultiMapPtrList()
0275     {
0276         PtrListEntry *t_next, *t_current = m_first;
0277         while (t_current) {
0278             t_next = t_current->next;
0279             delete t_current;
0280             t_current = t_next;
0281         }
0282     }
0283     void append(T *e)
0284     {
0285         PtrListEntry *t_last = 0, *t_current = m_first;
0286         int count = 0;
0287         while (t_current) {
0288             if (t_current->insert(e)) {
0289                 return;
0290             }
0291             t_last = t_current;
0292             t_current = t_current->next;
0293             count++;
0294         }
0295         // Create new hash-set
0296         unsigned int newsize = m_first->log_size + 1;
0297         if (newsize > MAX_PTRLIST_SIZE) {
0298             newsize = MAX_PTRLIST_SIZE;
0299         }
0300         t_current = new PtrListEntry(newsize);
0301         bool t = t_current->insert(e);
0302         assert(t);
0303         // Prepend it to the list, for insert effeciency
0304         t_current->next = m_first;
0305         m_first = t_current;
0306         // ### rehash some of the smaller sets
0307         /*
0308         if (count > 4) {
0309             // rehash the last in the new
0310             t_current->insert(t_last);
0311         }*/
0312     }
0313     void remove(T *e)
0314     {
0315         PtrListEntry *t_next, *t_last = 0, *t_current = m_first;
0316         // Remove has to check every PtrEntry.
0317         while (t_current) {
0318             t_next = t_current->next;
0319             if (t_current->remove(e) && t_current->isEmpty()) {
0320                 if (t_last) {
0321                     t_last->next = t_current->next;
0322                 } else {
0323                     assert(m_first == t_current);
0324                     m_first = t_current->next;
0325                 }
0326                 delete t_current;
0327             } else {
0328                 t_last = t_current;
0329             }
0330             t_current = t_next;
0331         }
0332     }
0333     bool contains(T *e)
0334     {
0335         PtrListEntry *t_current = m_first;
0336         while (t_current) {
0337             if (t_current->contains(e)) {
0338                 return true;
0339             }
0340             t_current = t_current->next;
0341         }
0342         return false;
0343     }
0344     bool isEmpty()
0345     {
0346         if (!m_first) {
0347             return true;
0348         }
0349         PtrListEntry *t_current = m_first;
0350         while (t_current) {
0351             if (!t_current->isEmpty()) {
0352                 return false;
0353             }
0354             t_current = t_current->next;
0355         }
0356         return true;
0357     }
0358     unsigned int count() const
0359     {
0360         unsigned int t_count = 0;
0361         PtrListEntry *t_current = m_first;
0362         while (t_current) {
0363             t_count += t_current->count;
0364             t_current = t_current->next;
0365         }
0366         return t_count;
0367     }
0368 // Iterator functions:
0369     T *first()
0370     {
0371         m_current = m_first;
0372         m_pos = 0;
0373         // skip holes
0374         if (m_current && !m_current->at(m_pos)) {
0375             return next();
0376         } else {
0377             return current();
0378         }
0379     }
0380     T *current()
0381     {
0382         if (!m_current) {
0383             return (T *)0;
0384         } else {
0385             return (T *)m_current->at(m_pos);
0386         }
0387     }
0388     T *next()
0389     {
0390         if (!m_current) {
0391             return (T *)0;
0392         }
0393         m_pos++;
0394         if (m_pos >= m_current->size()) {
0395             m_current = m_current->next;
0396             m_pos = 0;
0397         }
0398         // skip holes
0399         if (m_current && !m_current->at(m_pos)) {
0400             return next();
0401         } else {
0402             return current();
0403         }
0404     }
0405 private:
0406     PtrListEntry *m_first;
0407 // iteration:
0408     PtrListEntry *m_current;
0409     unsigned int m_pos;
0410 };
0411 
0412 #undef START_PTRLIST_SIZE
0413 #undef MAX_PTRLIST_SIZE
0414 #endif