LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sal/rtl - hash.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 90 97 92.8 %
Date: 2013-07-09 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include "hash.hxx"
      22             : #include "strimp.hxx"
      23             : #include <osl/diagnose.h>
      24             : #include <sal/macros.h>
      25             : 
      26             : struct StringHashTableImpl {
      27             :     sal_uInt32    nEntries;
      28             :     sal_uInt32    nSize;
      29             :     rtl_uString **pData;
      30             : };
      31             : 
      32             : typedef StringHashTableImpl StringHashTable;
      33             : 
      34             : // Only for use in the implementation
      35             : static StringHashTable *rtl_str_hash_new (sal_uInt32 nSize);
      36             : static void rtl_str_hash_free (StringHashTable *pHash);
      37             : 
      38             : StringHashTable *
      39      346127 : getHashTable ()
      40             : {
      41             :     static StringHashTable *pInternPool = NULL;
      42      346127 :     if (pInternPool == NULL) {
      43          67 :         static StringHashTable* pHash = rtl_str_hash_new(1024);
      44          67 :         pInternPool = pHash;
      45             :     }
      46      346127 :     return pInternPool;
      47             : }
      48             : 
      49             : // Better / smaller / faster hash set ....
      50             : 
      51             : // TODO: add bottom bit-set list terminator to string list
      52             : 
      53             : static sal_uInt32
      54         183 : getNextSize (sal_uInt32 nSize)
      55             : {
      56             :     // Sedgewick - Algorithms in C P577.
      57             :     static const sal_uInt32 nPrimes[] = { 1021, 2039, 4093, 8191, 16381, 32749,
      58             :                                           65521, 131071,262139, 524287, 1048573,
      59             :                                           2097143, 4194301, 8388593, 16777213,
      60             :                                           33554393, 67108859, 134217689 };
      61             : 
      62         644 :     for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(nPrimes); i++)
      63             :     {
      64         644 :         if (nPrimes[i] > nSize)
      65         183 :             return nPrimes[i];
      66             :     }
      67           0 :     return nSize * 2;
      68             : }
      69             : 
      70             : static sal_uInt32
      71      512064 : hashString (rtl_uString *pString)
      72             : {
      73             :     return (sal_uInt32) rtl_ustr_hashCode_WithLength (pString->buffer,
      74      512064 :                                                       pString->length);
      75             : }
      76             : 
      77             : static StringHashTable *
      78         125 : rtl_str_hash_new (sal_uInt32 nSize)
      79             : {
      80         125 :     StringHashTable *pHash = (StringHashTable *)malloc (sizeof (StringHashTable));
      81             : 
      82         125 :     pHash->nEntries = 0;
      83         125 :     pHash->nSize = getNextSize (nSize);
      84         125 :     pHash->pData = (rtl_uString **) calloc (sizeof (rtl_uString *), pHash->nSize);
      85             : 
      86         125 :     return pHash;
      87             : }
      88             : 
      89             : static void
      90          58 : rtl_str_hash_free (StringHashTable *pHash)
      91             : {
      92          58 :     if (!pHash)
      93          58 :         return;
      94          58 :     if (pHash->pData)
      95           0 :         free (pHash->pData);
      96          58 :     free (pHash);
      97             : }
      98             : 
      99             : static void
     100      165995 : rtl_str_hash_insert_nonequal (StringHashTable   *pHash,
     101             :                               rtl_uString       *pString)
     102             : {
     103      165995 :     sal_uInt32  nHash = hashString (pString);
     104             :     sal_uInt32  n;
     105             : 
     106      165995 :     n = nHash % pHash->nSize;
     107      348351 :     while (pHash->pData[n] != NULL) {
     108       16361 :         n++;
     109       16361 :         if (n >= pHash->nSize)
     110           0 :             n = 0;
     111             :     }
     112      165995 :     pHash->pData[n] = pString;
     113      165995 : }
     114             : 
     115             : static void
     116          58 : rtl_str_hash_resize (sal_uInt32        nNewSize)
     117             : {
     118             :     sal_uInt32 i;
     119             :     StringHashTable *pNewHash;
     120          58 :     StringHashTable *pHash = getHashTable();
     121             : 
     122             :     OSL_ASSERT (nNewSize > pHash->nEntries);
     123             : 
     124          58 :     pNewHash = rtl_str_hash_new (nNewSize);
     125             : 
     126      278272 :     for (i = 0; i < pHash->nSize; i++)
     127             :     {
     128      278214 :         if (pHash->pData[i] != NULL)
     129      139078 :             rtl_str_hash_insert_nonequal (pNewHash, pHash->pData[i]);
     130             :     }
     131          58 :     pNewHash->nEntries = pHash->nEntries;
     132          58 :     free (pHash->pData);
     133          58 :     *pHash = *pNewHash;
     134          58 :     pNewHash->pData = NULL;
     135          58 :     rtl_str_hash_free (pNewHash);
     136          58 : }
     137             : 
     138             : static int
     139      275642 : compareEqual (rtl_uString *pStringA, rtl_uString *pStringB)
     140             : {
     141      275642 :     if (pStringA == pStringB)
     142      162864 :         return 1;
     143      112778 :     if (pStringA->length != pStringB->length)
     144       88217 :         return 0;
     145             :     return !rtl_ustr_compare_WithLength( pStringA->buffer, pStringA->length,
     146       24561 :                                          pStringB->buffer, pStringB->length);
     147             : }
     148             : 
     149             : 
     150             : rtl_uString *
     151      183205 : rtl_str_hash_intern (rtl_uString       *pString,
     152             :                      int                can_return)
     153             : {
     154      183205 :     sal_uInt32  nHash = hashString (pString);
     155             :     sal_uInt32  n;
     156             :     rtl_uString *pHashStr;
     157             : 
     158      183205 :     StringHashTable *pHash = getHashTable();
     159             : 
     160             :     // Should we resize ?
     161      183205 :     if (pHash->nEntries >= pHash->nSize/2)
     162          58 :         rtl_str_hash_resize (getNextSize(pHash->nSize));
     163             : 
     164      183205 :     n = nHash % pHash->nSize;
     165      445253 :     while ((pHashStr = pHash->pData[n]) != NULL) {
     166       99088 :         if (compareEqual (pHashStr, pString))
     167             :         {
     168       20245 :             rtl_uString_acquire (pHashStr);
     169       20245 :             return pHashStr;
     170             :         }
     171       78843 :         n++;
     172       78843 :         if (n >= pHash->nSize)
     173           1 :             n = 0;
     174             :     }
     175             : 
     176      162960 :     if (!can_return)
     177             :     {
     178       14723 :         rtl_uString *pCopy = NULL;
     179       14723 :         rtl_uString_newFromString( &pCopy, pString );
     180       14723 :         pString = pCopy;
     181       14723 :         if (!pString)
     182           0 :             return NULL;
     183             :     }
     184             : 
     185      162960 :     if (!SAL_STRING_IS_STATIC (pString))
     186      162960 :         pString->refCount |= SAL_STRING_INTERN_FLAG;
     187      162960 :     pHash->pData[n] = pString;
     188      162960 :     pHash->nEntries++;
     189             : 
     190      162960 :     return pString;
     191             : }
     192             : 
     193             : void
     194      162864 : rtl_str_hash_remove (rtl_uString       *pString)
     195             : {
     196             :     sal_uInt32   n;
     197      162864 :     sal_uInt32   nHash = hashString (pString);
     198             :     rtl_uString *pHashStr;
     199             : 
     200      162864 :     StringHashTable *pHash = getHashTable();
     201             : 
     202      162864 :     n = nHash % pHash->nSize;
     203      339418 :     while ((pHashStr = pHash->pData[n]) != NULL) {
     204      176554 :         if (compareEqual (pHashStr, pString))
     205      162864 :             break;
     206       13690 :         n++;
     207       13690 :         if (n >= pHash->nSize)
     208           0 :             n = 0;
     209             :     }
     210             :     OSL_ASSERT (pHash->pData[n] != 0);
     211      162864 :     if (pHash->pData[n] == NULL)
     212      162864 :         return;
     213             : 
     214      162864 :     pHash->pData[n++] = NULL;
     215      162864 :     pHash->nEntries--;
     216             : 
     217      162864 :     if (n >= pHash->nSize)
     218           0 :         n = 0;
     219             : 
     220      352645 :     while ((pHashStr = pHash->pData[n]) != NULL) {
     221       26917 :         pHash->pData[n] = NULL;
     222             :         // FIXME: rather unsophisticated and N^2 in chain-length, but robust.
     223       26917 :         rtl_str_hash_insert_nonequal (pHash, pHashStr);
     224       26917 :         n++;
     225       26917 :         if (n >= pHash->nSize)
     226           0 :             n = 0;
     227             :     }
     228             :     // FIXME: Should we down-size ?
     229             : }
     230             : 
     231             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10