bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / misc / sharedstringpool.cxx
blobe1dfe94453fd0d9deeb1bac5e1f14bd3f3c32fc7
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/.
8 */
10 #include <svl/sharedstringpool.hxx>
11 #include <svl/sharedstring.hxx>
12 #include <unotools/charclass.hxx>
13 #include <osl/mutex.hxx>
15 #include <unordered_map>
16 #include <unordered_set>
18 namespace svl {
20 namespace {
22 inline sal_Int32 getRefCount( const rtl_uString* p )
24 return (p->refCount & 0x3FFFFFFF);
27 typedef std::unordered_set<OUString, OUStringHash> StrHashType;
28 typedef std::pair<StrHashType::iterator, bool> InsertResultType;
29 typedef std::unordered_map<const rtl_uString*, OUString> StrStoreType;
31 InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr )
33 StrHashType::iterator it = rPool.find(rStr);
34 bool bInserted = false;
35 if (it == rPool.end())
37 // Not yet in the pool.
38 std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr);
39 if (!r.second)
40 // Insertion failed.
41 return InsertResultType(rPool.end(), false);
43 it = r.first;
44 bInserted = true;
47 return InsertResultType(it, bInserted);
52 struct SharedStringPool::Impl
54 mutable osl::Mutex maMutex;
55 StrHashType maStrPool;
56 StrHashType maStrPoolUpper;
57 StrStoreType maStrStore;
58 const CharClass* mpCharClass;
60 Impl( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
63 SharedStringPool::SharedStringPool( const CharClass* pCharClass ) :
64 mpImpl(new Impl(pCharClass)) {}
66 SharedStringPool::~SharedStringPool()
68 delete mpImpl;
71 SharedString SharedStringPool::intern( const OUString& rStr )
73 osl::MutexGuard aGuard(&mpImpl->maMutex);
75 InsertResultType aRes = findOrInsert(mpImpl->maStrPool, rStr);
76 if (aRes.first == mpImpl->maStrPool.end())
77 // Insertion failed.
78 return SharedString();
80 rtl_uString* pOrig = aRes.first->pData;
82 if (!mpImpl->mpCharClass)
83 // We don't track case insensitive strings.
84 return SharedString(pOrig, NULL);
86 if (!aRes.second)
88 // No new string has been inserted. Return the existing string in the pool.
89 StrStoreType::iterator it = mpImpl->maStrStore.find(pOrig);
90 if (it == mpImpl->maStrStore.end())
91 return SharedString();
93 rtl_uString* pUpper = it->second.pData;
94 return SharedString(pOrig, pUpper);
97 // This is a new string insertion. Establish mapping to upper-case variant.
99 OUString aUpper = mpImpl->mpCharClass->uppercase(rStr);
100 aRes = findOrInsert(mpImpl->maStrPoolUpper, aUpper);
101 if (aRes.first == mpImpl->maStrPoolUpper.end())
102 // Failed to insert or fetch upper-case variant. Should never happen.
103 return SharedString();
105 mpImpl->maStrStore.insert(StrStoreType::value_type(pOrig, *aRes.first));
107 return SharedString(pOrig, aRes.first->pData);
110 void SharedStringPool::purge()
112 osl::MutexGuard aGuard(&mpImpl->maMutex);
114 StrHashType aNewStrPool;
115 StrHashType::iterator it = mpImpl->maStrPool.begin(), itEnd = mpImpl->maStrPool.end();
116 for (; it != itEnd; ++it)
118 const rtl_uString* p = it->pData;
119 if (getRefCount(p) == 1)
121 // Remove it from the upper string map. This should unref the
122 // upper string linked to this original string.
123 mpImpl->maStrStore.erase(p);
125 else
126 // Still referenced outside the pool. Keep it.
127 aNewStrPool.insert(*it);
130 mpImpl->maStrPool.swap(aNewStrPool);
132 aNewStrPool.clear(); // for re-use.
134 // Purge the upper string pool as well.
135 it = mpImpl->maStrPoolUpper.begin();
136 itEnd = mpImpl->maStrPoolUpper.end();
137 for (; it != itEnd; ++it)
139 const rtl_uString* p = it->pData;
140 if (getRefCount(p) > 1)
141 aNewStrPool.insert(*it);
144 mpImpl->maStrPoolUpper.swap(aNewStrPool);
147 size_t SharedStringPool::getCount() const
149 osl::MutexGuard aGuard(&mpImpl->maMutex);
150 return mpImpl->maStrPool.size();
153 size_t SharedStringPool::getCountIgnoreCase() const
155 osl::MutexGuard aGuard(&mpImpl->maMutex);
156 return mpImpl->maStrPoolUpper.size();
161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */