LCOV - code coverage report
Current view: top level - svl/source/misc - sharedstringpool.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 59 64 92.2 %
Date: 2015-06-13 12:38:46 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             : 
      10             : #include <svl/sharedstringpool.hxx>
      11             : #include <svl/sharedstring.hxx>
      12             : #include <unotools/charclass.hxx>
      13             : #include <osl/mutex.hxx>
      14             : 
      15             : #include <unordered_map>
      16             : #include <unordered_set>
      17             : 
      18             : namespace svl {
      19             : 
      20             : namespace {
      21             : 
      22          56 : inline sal_Int32 getRefCount( const rtl_uString* p )
      23             : {
      24          56 :     return (p->refCount & 0x3FFFFFFF);
      25             : }
      26             : 
      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;
      30             : 
      31       99112 : InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr )
      32             : {
      33       99112 :     StrHashType::iterator it = rPool.find(rStr);
      34       99112 :     bool bInserted = false;
      35       99112 :     if (it == rPool.end())
      36             :     {
      37             :         // Not yet in the pool.
      38       15763 :         std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr);
      39       15763 :         if (!r.second)
      40             :             // Insertion failed.
      41           0 :             return InsertResultType(rPool.end(), false);
      42             : 
      43       15763 :         it = r.first;
      44       15763 :         bInserted = true;
      45             :     }
      46             : 
      47       99112 :     return InsertResultType(it, bInserted);
      48             : }
      49             : 
      50             : }
      51             : 
      52        2289 : struct SharedStringPool::Impl
      53             : {
      54             :     mutable osl::Mutex maMutex;
      55             :     StrHashType maStrPool;
      56             :     StrHashType maStrPoolUpper;
      57             :     StrStoreType maStrStore;
      58             :     const CharClass* mpCharClass;
      59             : 
      60        2322 :     explicit Impl( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
      61             : };
      62             : 
      63        2322 : SharedStringPool::SharedStringPool( const CharClass* pCharClass ) :
      64        2322 :     mpImpl(new Impl(pCharClass)) {}
      65             : 
      66        2289 : SharedStringPool::~SharedStringPool()
      67             : {
      68        2289 :     delete mpImpl;
      69        2289 : }
      70             : 
      71       91189 : SharedString SharedStringPool::intern( const OUString& rStr )
      72             : {
      73       91189 :     osl::MutexGuard aGuard(&mpImpl->maMutex);
      74             : 
      75       91189 :     InsertResultType aRes = findOrInsert(mpImpl->maStrPool, rStr);
      76       91189 :     if (aRes.first == mpImpl->maStrPool.end())
      77             :         // Insertion failed.
      78           0 :         return SharedString();
      79             : 
      80       91189 :     rtl_uString* pOrig = aRes.first->pData;
      81             : 
      82       91189 :     if (!mpImpl->mpCharClass)
      83             :         // We don't track case insensitive strings.
      84           0 :         return SharedString(pOrig, NULL);
      85             : 
      86       91189 :     if (!aRes.second)
      87             :     {
      88             :         // No new string has been inserted. Return the existing string in the pool.
      89       83266 :         StrStoreType::iterator it = mpImpl->maStrStore.find(pOrig);
      90       83266 :         if (it == mpImpl->maStrStore.end())
      91           0 :             return SharedString();
      92             : 
      93       83266 :         rtl_uString* pUpper = it->second.pData;
      94       83266 :         return SharedString(pOrig, pUpper);
      95             :     }
      96             : 
      97             :     // This is a new string insertion. Establish mapping to upper-case variant.
      98             : 
      99       15846 :     OUString aUpper = mpImpl->mpCharClass->uppercase(rStr);
     100        7923 :     aRes = findOrInsert(mpImpl->maStrPoolUpper, aUpper);
     101        7923 :     if (aRes.first == mpImpl->maStrPoolUpper.end())
     102             :         // Failed to insert or fetch upper-case variant. Should never happen.
     103           0 :         return SharedString();
     104             : 
     105        7923 :     mpImpl->maStrStore.insert(StrStoreType::value_type(pOrig, *aRes.first));
     106             : 
     107       99112 :     return SharedString(pOrig, aRes.first->pData);
     108             : }
     109             : 
     110          12 : void SharedStringPool::purge()
     111             : {
     112          12 :     osl::MutexGuard aGuard(&mpImpl->maMutex);
     113             : 
     114          24 :     StrHashType aNewStrPool;
     115          12 :     StrHashType::iterator it = mpImpl->maStrPool.begin(), itEnd = mpImpl->maStrPool.end();
     116          47 :     for (; it != itEnd; ++it)
     117             :     {
     118          35 :         const rtl_uString* p = it->pData;
     119          35 :         if (getRefCount(p) == 1)
     120             :         {
     121             :             // Remove it from the upper string map.  This should unref the
     122             :             // upper string linked to this original string.
     123          11 :             mpImpl->maStrStore.erase(p);
     124             :         }
     125             :         else
     126             :             // Still referenced outside the pool. Keep it.
     127          24 :             aNewStrPool.insert(*it);
     128             :     }
     129             : 
     130          12 :     mpImpl->maStrPool.swap(aNewStrPool);
     131             : 
     132          12 :     aNewStrPool.clear(); // for re-use.
     133             : 
     134             :     // Purge the upper string pool as well.
     135          12 :     it = mpImpl->maStrPoolUpper.begin();
     136          12 :     itEnd = mpImpl->maStrPoolUpper.end();
     137          33 :     for (; it != itEnd; ++it)
     138             :     {
     139          21 :         const rtl_uString* p = it->pData;
     140          21 :         if (getRefCount(p) > 1)
     141          16 :             aNewStrPool.insert(*it);
     142             :     }
     143             : 
     144          24 :     mpImpl->maStrPoolUpper.swap(aNewStrPool);
     145          12 : }
     146             : 
     147          14 : size_t SharedStringPool::getCount() const
     148             : {
     149          14 :     osl::MutexGuard aGuard(&mpImpl->maMutex);
     150          14 :     return mpImpl->maStrPool.size();
     151             : }
     152             : 
     153          14 : size_t SharedStringPool::getCountIgnoreCase() const
     154             : {
     155          14 :     osl::MutexGuard aGuard(&mpImpl->maMutex);
     156          14 :     return mpImpl->maStrPoolUpper.size();
     157             : }
     158             : 
     159             : }
     160             : 
     161             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11