Update git submodules
[LibreOffice.git] / sal / rtl / hash.cxx
blob7cfc443cb972949d1214b4d6a9b93afec7ee3fc4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <stdlib.h>
24 #include "hash.hxx"
25 #include "strimp.hxx"
26 #include <osl/diagnose.h>
28 namespace {
30 struct StringHashTableImpl {
31 sal_uInt32 nEntries;
32 sal_uInt32 nSize;
33 rtl_uString **pData;
38 typedef StringHashTableImpl StringHashTable;
40 // Only for use in the implementation
41 static StringHashTable *rtl_str_hash_new(sal_uInt32 nSize);
42 static void rtl_str_hash_free(StringHashTable *pHash);
44 static StringHashTable * getHashTable()
46 static StringHashTable* pInternPool = rtl_str_hash_new(1024);
47 return pInternPool;
50 // Better / smaller / faster hash set...
52 // TODO: add bottom bit-set list terminator to string list
54 static sal_uInt32 getNextSize(sal_uInt32 nSize)
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 };
62 for (sal_uInt32 nPrime : nPrimes)
64 if (nPrime > nSize)
65 return nPrime;
67 return nSize * 2;
70 static sal_uInt32 hashString(rtl_uString *pString)
72 return static_cast<sal_uInt32>(rtl_ustr_hashCode_WithLength(pString->buffer,
73 pString->length));
76 static StringHashTable * rtl_str_hash_new(sal_uInt32 nSize)
78 StringHashTable *pHash = static_cast<StringHashTable *>(malloc(sizeof(StringHashTable)));
80 pHash->nEntries = 0;
81 pHash->nSize = getNextSize (nSize);
82 pHash->pData = static_cast< rtl_uString ** >(calloc(sizeof(rtl_uString *), pHash->nSize));
84 return pHash;
87 static void rtl_str_hash_free(StringHashTable *pHash)
89 if (!pHash)
90 return;
92 if (pHash->pData)
93 free(pHash->pData);
95 free(pHash);
98 static void
99 rtl_str_hash_insert_nonequal(StringHashTable *pHash,
100 rtl_uString *pString)
102 sal_uInt32 nHash = hashString(pString);
103 sal_uInt32 n;
105 n = nHash % pHash->nSize;
106 while (pHash->pData[n])
108 n++;
109 if (n >= pHash->nSize)
110 n = 0;
112 pHash->pData[n] = pString;
115 static void rtl_str_hash_resize(sal_uInt32 nNewSize)
117 sal_uInt32 i;
118 StringHashTable *pNewHash;
119 StringHashTable *pHash = getHashTable();
121 OSL_ASSERT(nNewSize > pHash->nEntries);
123 pNewHash = rtl_str_hash_new(nNewSize);
125 for (i = 0; i < pHash->nSize; i++)
127 if (pHash->pData[i])
128 rtl_str_hash_insert_nonequal(pNewHash, pHash->pData[i]);
131 pNewHash->nEntries = pHash->nEntries;
132 free(pHash->pData);
133 *pHash = *pNewHash;
134 pNewHash->pData = nullptr;
135 rtl_str_hash_free(pNewHash);
138 static bool compareEqual(rtl_uString *pStringA, rtl_uString *pStringB)
140 if (pStringA == pStringB)
141 return true;
143 if (pStringA->length != pStringB->length)
144 return false;
146 return !rtl_ustr_compare_WithLength( pStringA->buffer, pStringA->length,
147 pStringB->buffer, pStringB->length);
150 rtl_uString * rtl_str_hash_intern (
151 rtl_uString *pString,
152 int can_return)
154 sal_uInt32 nHash = hashString(pString);
155 sal_uInt32 n;
156 rtl_uString *pHashStr;
158 StringHashTable *pHash = getHashTable();
160 // Should we resize ?
161 if (pHash->nEntries >= pHash->nSize/2)
162 rtl_str_hash_resize(getNextSize(pHash->nSize));
164 n = nHash % pHash->nSize;
165 while ((pHashStr = pHash->pData[n]))
167 if (compareEqual(pHashStr, pString))
169 rtl_uString_acquire(pHashStr);
170 return pHashStr;
173 n++;
174 if (n >= pHash->nSize)
175 n = 0;
178 if (!can_return)
180 rtl_uString *pCopy = nullptr;
181 rtl_uString_newFromString( &pCopy, pString );
182 pString = pCopy;
184 if (!pString)
185 return nullptr;
188 if (!SAL_STRING_IS_STATIC(pString))
189 pString->refCount |= SAL_STRING_INTERN_FLAG;
191 pHash->pData[n] = pString;
192 pHash->nEntries++;
194 return pString;
197 void rtl_str_hash_remove(rtl_uString *pString)
199 sal_uInt32 n;
200 sal_uInt32 nHash = hashString(pString);
201 rtl_uString *pHashStr;
203 StringHashTable *pHash = getHashTable();
205 n = nHash % pHash->nSize;
206 while ((pHashStr = pHash->pData[n]))
208 if (compareEqual(pHashStr, pString))
209 break;
211 n++;
213 if (n >= pHash->nSize)
214 n = 0;
217 OSL_ASSERT(pHash->pData[n]);
218 if (!pHash->pData[n])
219 return;
221 pHash->pData[n++] = nullptr;
222 pHash->nEntries--;
224 if (n >= pHash->nSize)
225 n = 0;
227 while ((pHashStr = pHash->pData[n]))
229 pHash->pData[n] = nullptr;
230 // FIXME: rather unsophisticated and N^2 in chain-length, but robust.
231 rtl_str_hash_insert_nonequal(pHash, pHashStr);
232 n++;
234 if (n >= pHash->nSize)
235 n = 0;
237 // FIXME: Should we down-size ?
240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */