1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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
);
41 return InsertResultType(rPool
.end(), false);
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()
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())
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
);
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
);
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: */