• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

ksycocadict.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *
00004  *  This library is free software; you can redistribute it and/or
00005  *  modify it under the terms of the GNU Library General Public
00006  *  License version 2 as published by the Free Software Foundation;
00007  *
00008  *  This library is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  *  Library General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU Library General Public License
00014  *  along with this library; see the file COPYING.LIB.  If not, write to
00015  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  *  Boston, MA 02110-1301, USA.
00017  **/
00018 
00019 #include "ksycocadict.h"
00020 #include "ksycocaentry.h"
00021 #include "ksycoca.h"
00022 
00023 #include <qptrlist.h>
00024 #include <qvaluelist.h>
00025 #include <kdebug.h>
00026 #include <stdlib.h>
00027 
00028 namespace
00029 {
00030 struct string_entry {
00031   string_entry(QString _key, KSycocaEntry *_payload) 
00032   { keyStr = _key; key = keyStr.unicode(); length = keyStr.length(); payload = _payload; hash = 0; }
00033   uint hash;
00034   int length;
00035   const QChar *key;
00036   QString keyStr;
00037   KSycocaEntry *payload;
00038 };
00039 }
00040 
00041 template class QPtrList<string_entry>;
00042 
00043 class KSycocaDictStringList : public QPtrList<string_entry>
00044 {
00045 public:
00046    KSycocaDictStringList();
00047 };
00048 
00049 KSycocaDictStringList::KSycocaDictStringList()
00050 {
00051    setAutoDelete(true);
00052 }
00053 
00054 KSycocaDict::KSycocaDict()
00055   : d(0), mStr(0), mOffset(0)
00056 {
00057 }
00058 
00059 KSycocaDict::KSycocaDict(QDataStream *str, int offset)
00060   : d(0), mStr(str), mOffset(offset)
00061 {
00062    Q_UINT32 test1, test2;
00063    str->device()->at(offset);
00064    (*str) >> test1 >> test2;
00065    if ((test1 > 0x000fffff) || (test2 > 1024))
00066    {
00067        KSycoca::flagError();
00068        mHashTableSize = 0;
00069        mOffset = 0;
00070        return;
00071    }
00072 
00073    str->device()->at(offset);
00074    (*str) >> mHashTableSize;
00075    (*str) >> mHashList;
00076    mOffset = str->device()->at(); // Start of hashtable
00077 }
00078 
00079 KSycocaDict::~KSycocaDict()
00080 {
00081    delete d;
00082 }
00083 
00084 void 
00085 KSycocaDict::add(const QString &key, KSycocaEntry *payload)
00086 {
00087    if (key.isEmpty()) return; // Not allowed (should never happen)
00088    if (!payload) return; // Not allowed!
00089    if (!d)
00090    {
00091        d = new KSycocaDictStringList();
00092    }
00093 
00094    string_entry *entry= new string_entry(key, payload);
00095    d->append(entry);
00096 }
00097 
00098 void 
00099 KSycocaDict::remove(const QString &key)
00100 {
00101    if (d)
00102    {
00103       for(string_entry *entry=d->first(); entry; entry = d->next())
00104       {
00105          if (entry->keyStr == key)
00106          {
00107             d->remove();
00108             break;
00109          }
00110       }
00111    }
00112 }
00113    
00114 int 
00115 KSycocaDict::find_string(const QString &key )
00116 {
00117    //kdDebug(7011) << QString("KSycocaDict::find_string(%1)").arg(key) << endl;
00118 
00119    if (!mStr || !mOffset)
00120    {
00121       kdError(7011) << "No database available!" << endl;
00122       return 0;
00123    }
00124 
00125    if (mHashTableSize == 0)
00126       return 0; // Unlikely to find anything :-]
00127 
00128    // Read hash-table data 
00129    uint hash = hashKey(key) % mHashTableSize;
00130    //kdDebug(7011) << QString("hash is %1").arg(hash) << endl;
00131 
00132    uint off = mOffset+sizeof(Q_INT32)*hash;
00133    //kdDebug(7011) << QString("off is %1").arg(off,8,16) << endl;
00134    mStr->device()->at( off );
00135 
00136    Q_INT32 offset;
00137    (*mStr) >> offset;
00138 
00139    //kdDebug(7011) << QString("offset is %1").arg(offset,8,16) << endl;
00140    if (offset == 0)
00141       return 0;
00142 
00143    if (offset > 0)
00144       return offset; // Positive ID
00145 
00146    // Lookup duplicate list.
00147    offset = -offset;
00148 
00149    mStr->device()->at(offset);
00150    //kdDebug(7011) << QString("Looking up duplicate list at %1").arg(offset,8,16) << endl;
00151    
00152    while(true)
00153    {
00154        (*mStr) >> offset;
00155        if (offset == 0) break;
00156        QString dupkey;
00157        (*mStr) >> dupkey;
00158        //kdDebug(7011) << QString(">> %1 %2").arg(offset,8,16).arg(dupkey) << endl;
00159        if (dupkey == key) return offset;
00160    }
00161    //kdWarning(7011) << "Not found!" << endl;
00162 
00163    return 0;
00164 }
00165    
00166 uint 
00167 KSycocaDict::count()
00168 {
00169    if (!d) return 0;
00170 
00171    return d->count();
00172 }
00173 
00174 void 
00175 KSycocaDict::clear()
00176 {
00177    delete d;
00178    d = 0;
00179 }
00180 
00181 uint
00182 KSycocaDict::hashKey( const QString &key)
00183 {
00184    int l = key.length();
00185    register uint h = 0;
00186   
00187    for(uint i = 0; i < mHashList.count(); i++)
00188    {
00189       int pos = mHashList[i];
00190       if (pos < 0)
00191       {
00192          pos = -pos-1;
00193          if (pos < l)
00194             h = ((h * 13) + (key[l-pos].cell() % 29)) & 0x3ffffff;
00195       } 
00196       else
00197       {
00198          pos = pos-1;
00199          if (pos < l)
00200             h = ((h * 13) + (key[pos].cell() % 29)) & 0x3ffffff;
00201       }
00202    }
00203    return h;
00204 }
00205 
00206 //
00207 // Calculate the diversity of the strings at position 'pos'
00208 static int 
00209 calcDiversity(KSycocaDictStringList *d, int pos, int sz)
00210 {
00211    if (pos == 0) return 0;
00212    bool *matrix = (bool *) calloc(sz, sizeof(bool));
00213    uint usz = sz;
00214 
00215    if (pos < 0)
00216    {
00217       pos = -pos-1;
00218       for(string_entry *entry=d->first(); entry; entry = d->next())
00219       {
00220     register int l = entry->length;
00221          if (pos < l && pos != 0)
00222          {
00223            register uint hash = ((entry->hash * 13) + (entry->key[l-pos].cell() % 29)) & 0x3ffffff;
00224        matrix[ hash % usz ] = true;
00225          }
00226       }
00227    }
00228    else
00229    {
00230       pos = pos-1;
00231       for(string_entry *entry=d->first(); entry; entry = d->next())
00232       {
00233          if (pos < entry->length)
00234          {
00235             register uint hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3ffffff;
00236             matrix[ hash % usz ] = true;
00237          }
00238       }
00239    }
00240    int diversity = 0;
00241    for(int i=0;i< sz;i++)
00242       if (matrix[i]) diversity++;
00243    
00244    free((void *) matrix);
00245 
00246    return diversity;
00247 }
00248 
00249 //
00250 // Add the diversity of the strings at position 'pos'
00251 static void 
00252 addDiversity(KSycocaDictStringList *d, int pos)
00253 {
00254    if (pos == 0) return;
00255    if (pos < 0)
00256    {
00257       pos = -pos-1;
00258       for(string_entry *entry=d->first(); entry; entry = d->next())
00259       {
00260          register int l = entry->length;
00261          if (pos < l)
00262             entry->hash = ((entry->hash * 13) + (entry->key[l-pos].cell() % 29)) & 0x3fffffff;
00263       }
00264    }
00265    else
00266    {
00267       pos = pos - 1;
00268       for(string_entry *entry=d->first(); entry; entry = d->next())
00269       {
00270          if (pos < entry->length)
00271             entry->hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3fffffff;
00272       }
00273    }
00274 }
00275 
00276 
00277 void 
00278 KSycocaDict::save(QDataStream &str)
00279 {
00280    if (count() == 0)
00281    {
00282       mHashTableSize = 0;
00283       mHashList.clear();
00284       str << mHashTableSize;
00285       str << mHashList;
00286       return;
00287    }
00288 
00289    mOffset = str.device()->at();
00290 
00291    //kdDebug(7011) << QString("KSycocaDict: %1 entries.").arg(count()) << endl;
00292 
00293    //kdDebug(7011) << "Calculating hash keys.." << endl;
00294 
00295    int maxLength = 0;
00296    //kdDebug(7011) << "Finding maximum string length" << endl;
00297    for(string_entry *entry=d->first(); entry; entry = d->next())
00298    {
00299       entry->hash = 0;
00300       if (entry->length > maxLength)
00301          maxLength = entry->length;
00302    }
00303 
00304    //kdDebug(7011) << QString("Max string length = %1").arg(maxLength) << endl;
00305 
00306    // use "almost prime" number for sz (to calculate diversity) and later
00307    // for the table size of big tables
00308    // int sz = d->count()*5-1;
00309    register unsigned int sz = count()*4 + 1;
00310    while(!(((sz % 3) && (sz % 5) && (sz % 7) && (sz % 11) && (sz % 13)))) sz+=2;
00311 
00312    int maxDiv = 0;
00313    int maxPos = 0;
00314    int lastDiv = 0;
00315 
00316    mHashList.clear();
00317 
00318    // try to limit diversity scan by "predicting" positions
00319    // with high diversity
00320    int *oldvec=new int[maxLength*2+1];
00321    for (int i=0; i<(maxLength*2+1); i++) oldvec[i]=0;
00322    int mindiv=0;
00323 
00324    while(true)
00325    {
00326       int divsum=0,divnum=0;
00327 
00328       maxDiv = 0;
00329       maxPos = 0;
00330       for(int pos=-maxLength; pos <= maxLength; pos++)
00331       {
00332          // cut off
00333          if (oldvec[pos+maxLength]<mindiv)
00334          { oldvec[pos+maxLength]=0; continue; }
00335 
00336          int diversity = calcDiversity(d, pos, sz);
00337          if (diversity > maxDiv)
00338          {
00339             maxDiv = diversity;
00340             maxPos = pos;
00341          }
00342          oldvec[pos+maxLength]=diversity;
00343          divsum+=diversity; divnum++;
00344       }
00345       // arbitrary cut-off value 3/4 of average seems to work
00346       if (divnum)
00347          mindiv=(3*divsum)/(4*divnum);
00348 
00349       if (maxDiv <= lastDiv)
00350          break;
00351       // qWarning("Max Div = %d at pos %d", maxDiv, maxPos);
00352       lastDiv = maxDiv;
00353       addDiversity(d, maxPos);
00354       mHashList.append(maxPos);
00355    }
00356 
00357    delete [] oldvec;
00358 
00359    for(string_entry *entry=d->first(); entry; entry = d->next())
00360    {
00361       entry->hash = hashKey(entry->keyStr);
00362    }
00363 // fprintf(stderr, "Calculating minimum table size..\n");
00364 
00365    mHashTableSize = sz;
00366 
00367    struct hashtable_entry {
00368       string_entry *entry;
00369       QPtrList<string_entry> *duplicates;
00370       int duplicate_offset;
00371    };
00372 
00373    hashtable_entry *hashTable = new hashtable_entry[ sz ];
00374 
00375    //kdDebug(7011) << "Clearing hashtable..." << endl;
00376    for (unsigned int i=0; i < sz; i++)
00377    {
00378       hashTable[i].entry = 0;
00379       hashTable[i].duplicates = 0;
00380    }
00381 
00382    //kdDebug(7011) << "Filling hashtable..." << endl;
00383    for(string_entry *entry=d->first(); entry; entry = d->next())
00384    {
00385       int hash = entry->hash % sz;
00386       if (!hashTable[hash].entry)
00387       { // First entry
00388          hashTable[hash].entry = entry;
00389       }
00390       else 
00391       {
00392          if (!hashTable[hash].duplicates)
00393          { // Second entry, build duplicate list.
00394             hashTable[hash].duplicates = new QPtrList<string_entry>();
00395             hashTable[hash].duplicates->append(hashTable[hash].entry);
00396             hashTable[hash].duplicate_offset = 0;
00397          }
00398          hashTable[hash].duplicates->append(entry);
00399       }
00400    }
00401 
00402    str << mHashTableSize;
00403    str << mHashList;
00404 
00405    mOffset = str.device()->at(); // mOffset points to start of hashTable
00406    //kdDebug(7011) << QString("Start of Hash Table, offset = %1").arg(mOffset,8,16) << endl;
00407 
00408    for(int pass = 1; pass <= 2; pass++)
00409    {
00410       str.device()->at(mOffset);
00411       //kdDebug(7011) << QString("Writing hash table (pass #%1)").arg(pass) << endl;
00412       for(uint i=0; i < mHashTableSize; i++)
00413       {
00414          Q_INT32 tmpid;
00415          if (!hashTable[i].entry)
00416             tmpid = (Q_INT32) 0;
00417          else if (!hashTable[i].duplicates)
00418             tmpid = (Q_INT32) hashTable[i].entry->payload->offset(); // Positive ID
00419          else
00420             tmpid = (Q_INT32) -hashTable[i].duplicate_offset; // Negative ID
00421          str << tmpid;
00422          //kdDebug(7011) << QString("Hash table : %1").arg(tmpid,8,16) << endl;
00423       }
00424       //kdDebug(7011) << QString("End of Hash Table, offset = %1").arg(str.device()->at(),8,16) << endl;
00425 
00426       //kdDebug(7011) << QString("Writing duplicate lists (pass #%1)").arg(pass) << endl;
00427       for(uint i=0; i < mHashTableSize; i++)
00428       {
00429          if (hashTable[i].duplicates)
00430          {
00431             QPtrList<string_entry> *dups = hashTable[i].duplicates;
00432             hashTable[i].duplicate_offset = str.device()->at();
00433 
00434             /*kdDebug(7011) << QString("Duplicate lists: Offset = %1 list_size = %2")                           .arg(hashTable[i].duplicate_offset,8,16).arg(dups->count()) << endl;
00435 */
00436             for(string_entry *dup = dups->first(); dup; dup=dups->next())
00437             {
00438                str << (Q_INT32) dup->payload->offset(); // Positive ID
00439                str << dup->keyStr;                      // Key (QString)
00440             }
00441             str << (Q_INT32) 0;               // End of list marker (0)
00442          }
00443       }
00444       //kdDebug(7011) << QString("End of Dict, offset = %1").arg(str.device()->at(),8,16) << endl;
00445    }
00446 
00447    //kdDebug(7011) << "Cleaning up hash table." << endl;
00448    for(uint i=0; i < mHashTableSize; i++)
00449    {
00450       delete hashTable[i].duplicates;
00451    }
00452    delete [] hashTable;
00453 }
00454 

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal