diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2024-07-01 12:32:42 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2024-07-01 17:07:35 +0200 |
commit | 001d8041aebfaf460bf8420af311e240a9d42183 (patch) | |
tree | d85b6565ad22157338c61053d2b24db3a73e303f /svl | |
parent | af2175bb87b8e8a7184916e110e2b22ec542357d (diff) |
move global item pool to own source file
Change-Id: I91365c844370ef423630d5679cadd91cbf0597b0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169799
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'svl')
-rw-r--r-- | svl/Library_svl.mk | 1 | ||||
-rw-r--r-- | svl/source/items/globalpool.cxx | 453 | ||||
-rw-r--r-- | svl/source/items/itemset.cxx | 402 | ||||
-rw-r--r-- | svl/source/items/poolitem.cxx | 10 |
4 files changed, 454 insertions, 412 deletions
diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk index 04abb8c6cf3a..d848c2bde516 100644 --- a/svl/Library_svl.mk +++ b/svl/Library_svl.mk @@ -119,6 +119,7 @@ $(eval $(call gb_Library_add_exception_objects,svl,\ svl/source/items/custritm \ svl/source/items/flagitem \ svl/source/items/globalnameitem \ + svl/source/items/globalpool \ svl/source/items/grabbagitem \ svl/source/items/ilstitem \ svl/source/items/imageitm \ diff --git a/svl/source/items/globalpool.cxx b/svl/source/items/globalpool.cxx new file mode 100644 index 000000000000..66bc650a2791 --- /dev/null +++ b/svl/source/items/globalpool.cxx @@ -0,0 +1,453 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svl/itemset.hxx> +#include <svl/itempool.hxx> +#include <svl/setitem.hxx> +#include <sal/log.hxx> + +static bool g_bDisableItemInstanceManager(getenv("SVL_DISABLE_ITEM_INSTANCE_MANAGER")); +static bool g_bShareImmediately(getenv("SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY")); +#define NUMBER_OF_UNSHARED_INSTANCES (50) + +#ifdef DBG_UTIL + +// <WhichID, <number of entries, typeid_name>> +typedef std::unordered_map<sal_uInt16, std::pair<sal_uInt32, const char*>> HightestUsage; +static HightestUsage aHightestUsage; + +static void addUsage(const SfxPoolItem& rCandidate) +{ + HightestUsage::iterator aHit(aHightestUsage.find(rCandidate.Which())); + if (aHit == aHightestUsage.end()) + { + aHightestUsage.insert({ rCandidate.Which(), { 1, typeid(rCandidate).name() } }); + return; + } + aHit->second.first++; +} + +void listSfxPoolItemsWithHighestUsage(sal_uInt16 nNum) +{ + struct sorted + { + sal_uInt16 nWhich; + sal_uInt32 nUsage; + const char* pType; + sorted(sal_uInt16 _nWhich, sal_uInt32 _nUsage, const char* _pType) + : nWhich(_nWhich) + , nUsage(_nUsage) + , pType(_pType) + { + } + bool operator<(const sorted& rDesc) const { return nUsage > rDesc.nUsage; } + }; + std::vector<sorted> aSorted; + aSorted.reserve(aHightestUsage.size()); + for (const auto& rEntry : aHightestUsage) + aSorted.emplace_back(rEntry.first, rEntry.second.first, rEntry.second.second); + std::sort(aSorted.begin(), aSorted.end()); + sal_uInt16 a(0); + SAL_INFO("svl.items", + "ITEM: List of the " << nNum << " SfxPoolItems with highest non-RefCounted usages:"); + for (const auto& rEntry : aSorted) + { + SAL_INFO("svl.items", " ITEM(" << a << "): Which: " << rEntry.nWhich + << " Uses: " << rEntry.nUsage << " Type: " << rEntry.pType); + if (++a >= nNum) + break; + } +} + +#endif + +void DefaultItemInstanceManager::add(const SfxPoolItem& rItem) +{ + maRegistered[rItem.Which()].insert(&rItem); +} + +void DefaultItemInstanceManager::remove(const SfxPoolItem& rItem) +{ + maRegistered[rItem.Which()].erase(&rItem); +} + +// Class that implements global Item sharing. It uses rtti to +// associate every Item-derivation with a possible incarnation +// of a DefaultItemInstanceManager. This is the default, it will +// give direct implementations at the Items that overload +// getItemInstanceManager() preference. These are expected to +// return static instances of a derived implementation of a +// ItemInstanceManager. +// All in all there are now the following possibilities to support +// this for individual Item derivations: +// (1) Do nothing: +// In that case, if the Item is shareable, the new mechanism +// will kick in: It will start sharing the Item globally, +// but not immediately: After a defined amount of allowed +// non-shared occurrences (look for NUMBER_OF_UNSHARED_INSTANCES) +// an instance of the default ItemInstanceManager, a +// DefaultItemInstanceManager, will be incarnated and used. +// NOTE: Mixing shared/unshared instances is not a problem (we +// might even implement a kind of 're-hash' when this kicks in, +// but is not really needed). +// (2) Overload getItemInstanceManager for SfxPoolItem in a class +// derived from SfxPoolItem and... +// (2a) Return a static incarnation of DefaultItemInstanceManager to +// immediately start global sharing of that Item derivation. +// (2b) Implement and return your own implementation and static +// incarnation of ItemInstanceManager to do something better/ +// faster that the default implementation can do. Example: +// SvxFontItem, uses hashing now. +// There are two supported ENVVARs to use: +// (a) SVL_DISABLE_ITEM_INSTANCE_MANAGER: +// This disables the mechanism of global Item sharing completely. +// This can be used to test/check speed/memory needs compared with +// using it, but also may come in handy to check if evtl. errors/ +// regressions have to do with it. +// (b) SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY: +// This internally forces the NUMBER_OF_UNSHARED_INSTANCES to be +// ignored and start sharing ALL Item derivations instantly. +class InstanceManagerHelper +{ + typedef std::unordered_map<std::size_t, std::pair<sal_uInt16, DefaultItemInstanceManager*>> + managerTypeMap; + managerTypeMap maManagerPerType; + +public: + InstanceManagerHelper() {} + ~InstanceManagerHelper() + { + for (auto& rCandidate : maManagerPerType) + if (nullptr != rCandidate.second.second) + delete rCandidate.second.second; + } + + ItemInstanceManager* getOrCreateItemInstanceManager(const SfxPoolItem& rItem) + { + // deactivated? + if (g_bDisableItemInstanceManager) + return nullptr; + + // Item cannot be shared? + if (!rItem.isShareable()) + return nullptr; + + // Prefer getting an ItemInstanceManager directly from + // the Item: These are the extra implemented (and thus + // hopefully fastest) incarnations + ItemInstanceManager* pManager(rItem.getItemInstanceManager()); + + // Check for correct hash, there may be derivations of that class. + // Note that Managers from the Items are *not* added to local list, + // they are expected to be static instances at the Items + const std::size_t aHash(typeid(rItem).hash_code()); + if (nullptr != pManager && pManager->getClassHash() == aHash) + return pManager; + + // check local memory for existing entry + managerTypeMap::iterator aHit(maManagerPerType.find(aHash)); + + // no instance yet + if (aHit == maManagerPerType.end()) + { + // create a default one to start usage-counting + if (g_bShareImmediately) + { + // create, insert locally and immediately start sharing + DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager(aHash)); + maManagerPerType.insert({ aHash, std::make_pair(0, pNew) }); + return pNew; + } + + // start countdown from NUMBER_OF_UNSHARED_INSTANCES until zero is reached + maManagerPerType.insert( + { aHash, std::make_pair(NUMBER_OF_UNSHARED_INSTANCES, nullptr) }); + return nullptr; + } + + // if there is already an ItemInstanceManager incarnated, return it + if (nullptr != aHit->second.second) + return aHit->second.second; + + if (aHit->second.first > 0) + { + // still not the needed number of hits, countdown & return nullptr + aHit->second.first--; + return nullptr; + } + + // here the countdown is zero and there is not yet a ItemInstanceManager + // incarnated. Do so, register and return it + assert(nullptr == aHit->second.second); + DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager(aHash)); + aHit->second.second = pNew; + + return pNew; + } + + ItemInstanceManager* getExistingItemInstanceManager(const SfxPoolItem& rItem) + { + // deactivated? + if (g_bDisableItemInstanceManager) + return nullptr; + + // Item cannot be shared? + if (!rItem.isShareable()) + return nullptr; + + // Prefer getting an ItemInstanceManager directly from + // the Item: These are the extra implemented (and thus + // hopefully fastest) incarnations + ItemInstanceManager* pManager(rItem.getItemInstanceManager()); + + // Check for correct hash, there may be derivations of that class. + // Note that Managers from the Items are *not* added to local list, + // they are expected to be static instances at the Items + const std::size_t aHash(typeid(rItem).hash_code()); + if (nullptr != pManager && pManager->getClassHash() == aHash) + return pManager; + + // check local memory for existing entry + managerTypeMap::iterator aHit(maManagerPerType.find(aHash)); + + if (aHit == maManagerPerType.end()) + // no instance yet, return nullptr + return nullptr; + + // if there is already a ItemInstanceManager incarnated, return it + if (nullptr != aHit->second.second) + return aHit->second.second; + + // count-up needed number of hits again if item is released + if (aHit->second.first < NUMBER_OF_UNSHARED_INSTANCES) + aHit->second.first++; + + return nullptr; + } +}; + +// the single static instance that takes over that global Item sharing +static InstanceManagerHelper aInstanceManagerHelper; + +SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, + bool bPassingOwnership) +{ + if (nullptr == pSource) + // SfxItemState::UNKNOWN aka current default (nullptr) + // just use/return nullptr + return nullptr; + + if (pSource->isStaticDefault()) + // static default Items can just be used without RefCounting + // NOTE: This now includes IsInvalidItem/IsDisabledItem + return pSource; + + if (0 == pSource->Which()) + { + // There should be no Items with 0 == WhichID, but there are some + // constructed for dialog return values AKA result (look for SetReturnValue) + // these need to be cloned (currently...) + if (bPassingOwnership) + return pSource; + return pSource->Clone(); + } + + if (pSource->isDynamicDefault() && rPool.GetPoolDefaultItem(pSource->Which()) == pSource) + // dynamic defaults are not allowed to 'leave' the Pool they are + // defined for. We can check by comparing the PoolDefault (the + // PoolDefaultItem) to pSource by ptr compare (instance). When + // same Item we can use without RefCount. Else it will be cloned + // below the standard way. + return pSource; + +#ifdef DBG_UTIL + // remember WhichID due to being able to assert Clone() error(s) + const sal_uInt16 nWhich(pSource->Which()); +#endif + + if (SfxItemPool::IsSlot(pSource->Which())) + { + // SlotItems were always cloned in original (even when bPassingOwnership), + // so do that here, too (but without bPassingOwnership). + // They do not need to be registered at pool (actually impossible, pools + // do not have entries for SlotItems) so handle here early + if (!bPassingOwnership) + { + pSource = pSource->Clone(rPool.GetMasterPool()); + // ARGH! Found out that *some* ::Clone implementations fail to also clone the + // WhichID set at the original Item, e.g. SfxFrameItem. Assert, this is an error +#ifdef DBG_UTIL + assert(pSource->Which() == nWhich + && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); +#endif + } + + return pSource; + } + + // get the pool with which ItemSets have to work, plus get the + // pool at which the WhichID is defined, so calls to it do not + // have to do this repeatedly + SfxItemPool* pMasterPool(rPool.GetMasterPool()); + assert(nullptr != pMasterPool); + + // The Item itself is shareable when it is used/added at an instance + // that RefCounts the Item, SfxItemPool or SfxPoolItemHolder. Try + // to share items that are already shared + while (pSource->GetRefCount() > 0) + { + if (!pSource->isShareable()) + // not shareable, done + break; + + // SfxSetItems cannot be shared if they are in/use another pool + if (pSource->isSetItem() + && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool) + break; + + // If we get here we can share the Item + pSource->AddRef(); + return pSource; + } + + // try to get an ItemInstanceManager for global Item instance sharing + ItemInstanceManager* pManager(aInstanceManagerHelper.getOrCreateItemInstanceManager(*pSource)); + + // check if we can globally share the Item using an ItemInstanceManager + while (nullptr != pManager) + { + const SfxPoolItem* pAlternative(pManager->find(*pSource)); + if (nullptr == pAlternative) + // no already globally shared one found, done + break; + + // Here we do *not* need to check if it is an SfxSetItem + // and cannot be shared if they are in/use another pool: + // The SfxItemSet::operator== will check for SfxItemPools + // being equal, thus when found in global share the Pool + // cannot be equal + + // need to delete evtl. handed over ownership change Item + if (bPassingOwnership) + delete pSource; + + // If we get here we can share the Item + pAlternative->AddRef(); + return pAlternative; + } + + // check if the handed over and to be directly used item is a + // SfxSetItem, that would make it pool-dependent. It then must have + // the same target-pool, ensure that by the cost of cloning it + // (should not happen) + if (bPassingOwnership && pSource->isSetItem() + && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool) + { + const SfxPoolItem* pOld(pSource); + pSource = pSource->Clone(pMasterPool); +#ifdef DBG_UTIL + assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); +#endif + delete pOld; + } + +#ifdef DBG_UTIL + // create statistics for listSfxPoolItemsWithHighestUsage + addUsage(*pSource); +#endif + + // when we reach this line we know that we have to add/create a new item. If + // bPassingOwnership is given just use the item, else clone it + if (!bPassingOwnership) + { + pSource = pSource->Clone(pMasterPool); +#ifdef DBG_UTIL + assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); +#endif + } + + // increase RefCnt 0->1 + pSource->AddRef(); + + // check if we should register this Item for the global + // ItemInstanceManager mechanism (only for shareable Items) + if (nullptr != pManager) + pManager->add(*pSource); + + return pSource; +} + +void implCleanupItemEntry(const SfxPoolItem* pSource) +{ + if (nullptr == pSource) + // no entry, done + return; + + if (pSource->isStaticDefault()) + // static default Items can just be used without RefCounting + // NOTE: This now includes IsInvalidItem/IsDisabledItem + return; + + if (0 == pSource->Which()) + { + // There should be no Items with 0 == WhichID, but there are some + // constructed for dialog return values AKA result (look for SetReturnValue) + // and need to be deleted + delete pSource; + return; + } + + if (pSource->isDynamicDefault()) + // dynamic default Items can only be used without RefCounting + // when same pool. this is already checked at implCreateItemEntry, + // so it would have been cloned (and would no longer have this + // flag). So we can just return here + return; + + if (SfxItemPool::IsSlot(pSource->Which())) + { + // SlotItems are cloned, so delete + delete pSource; + return; + } + + if (1 < pSource->GetRefCount()) + { + // Still multiple references present, so just alter the RefCount + pSource->ReleaseRef(); + return; + } + + // try to get an ItemInstanceManager for global Item instance sharing + ItemInstanceManager* pManager(aInstanceManagerHelper.getExistingItemInstanceManager(*pSource)); + + // check if we should/can remove this Item from the global + // ItemInstanceManager mechanism + if (nullptr != pManager) + pManager->remove(*pSource); + + // decrease RefCnt before deleting (destructor asserts for it and that's + // good to find other errors) + pSource->ReleaseRef(); + + // delete Item + delete pSource; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx index b3a6dd8f68cf..523ffc857509 100644 --- a/svl/source/items/itemset.cxx +++ b/svl/source/items/itemset.cxx @@ -35,10 +35,6 @@ #include <svl/whiter.hxx> #include <svl/voiditem.hxx> -static bool g_bDisableItemInstanceManager(getenv("SVL_DISABLE_ITEM_INSTANCE_MANAGER")); -static bool g_bShareImmediately(getenv("SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY")); -#define NUMBER_OF_UNSHARED_INSTANCES (50) - #ifdef DBG_UTIL static size_t nAllocatedSfxItemSetCount(0); static size_t nUsedSfxItemSetCount(0); @@ -49,10 +45,6 @@ size_t getUsedSfxItemSetCount() { return nUsedSfxItemSetCount; } size_t getAllocatedSfxPoolItemHolderCount() { return nAllocatedSfxPoolItemHolderCount; } size_t getUsedSfxPoolItemHolderCount() { return nUsedSfxPoolItemHolderCount; } -// <WhichID, <number of entries, typeid_name>> -typedef std::unordered_map<sal_uInt16, std::pair<sal_uInt32, const char*>> HightestUsage; -static HightestUsage aHightestUsage; - // <TotalCount, <number of entries, sum of used count>> typedef std::unordered_map<sal_uInt16, std::pair<sal_uInt32, sal_uInt32>> ItemArrayUsage; static ItemArrayUsage aItemArrayUsage; @@ -69,42 +61,6 @@ static void addArrayUsage(sal_uInt16 nCount, sal_uInt16 nTotalCount) aHit->second.second += nCount; } -static void addUsage(const SfxPoolItem& rCandidate) -{ - HightestUsage::iterator aHit(aHightestUsage.find(rCandidate.Which())); - if (aHit == aHightestUsage.end()) - { - aHightestUsage.insert({rCandidate.Which(), {1, typeid(rCandidate).name()}}); - return; - } - aHit->second.first++; -} - -void listSfxPoolItemsWithHighestUsage(sal_uInt16 nNum) -{ - struct sorted { - sal_uInt16 nWhich; - sal_uInt32 nUsage; - const char* pType; - sorted(sal_uInt16 _nWhich, sal_uInt32 _nUsage, const char* _pType) - : nWhich(_nWhich), nUsage(_nUsage), pType(_pType) {} - bool operator<(const sorted& rDesc) const { return nUsage > rDesc.nUsage; } - }; - std::vector<sorted> aSorted; - aSorted.reserve(aHightestUsage.size()); - for (const auto& rEntry : aHightestUsage) - aSorted.emplace_back(rEntry.first, rEntry.second.first, rEntry.second.second); - std::sort(aSorted.begin(), aSorted.end()); - sal_uInt16 a(0); - SAL_INFO("svl.items", "ITEM: List of the " << nNum << " SfxPoolItems with highest non-RefCounted usages:"); - for (const auto& rEntry : aSorted) - { - SAL_INFO("svl.items", " ITEM(" << a << "): Which: " << rEntry.nWhich << " Uses: " << rEntry.nUsage << " Type: " << rEntry.pType); - if (++a >= nNum) - break; - } -} - SVL_DLLPUBLIC void listSfxItemSetUsage() { struct sorted { @@ -368,364 +324,6 @@ SfxItemSet::~SfxItemSet() m_aWhichRanges.reset(); } -// Class that implements global Item sharing. It uses rtti to -// associate every Item-derivation with a possible incarnation -// of a DefaultItemInstanceManager. This is the default, it will -// give direct implementations at the Items that overload -// getItemInstanceManager() preference. These are expected to -// return static instances of a derived implementation of a -// ItemInstanceManager. -// All in all there are now the following possibilities to support -// this for individual Item derivations: -// (1) Do nothing: -// In that case, if the Item is shareable, the new mechanism -// will kick in: It will start sharing the Item globally, -// but not immediately: After a defined amount of allowed -// non-shared occurrences (look for NUMBER_OF_UNSHARED_INSTANCES) -// an instance of the default ItemInstanceManager, a -// DefaultItemInstanceManager, will be incarnated and used. -// NOTE: Mixing shared/unshared instances is not a problem (we -// might even implement a kind of 're-hash' when this kicks in, -// but is not really needed). -// (2) Overload getItemInstanceManager for SfxPoolItem in a class -// derived from SfxPoolItem and... -// (2a) Return a static incarnation of DefaultItemInstanceManager to -// immediately start global sharing of that Item derivation. -// (2b) Implement and return your own implementation and static -// incarnation of ItemInstanceManager to do something better/ -// faster that the default implementation can do. Example: -// SvxFontItem, uses hashing now. -// There are two supported ENVVARs to use: -// (a) SVL_DISABLE_ITEM_INSTANCE_MANAGER: -// This disables the mechanism of global Item sharing completely. -// This can be used to test/check speed/memory needs compared with -// using it, but also may come in handy to check if evtl. errors/ -// regressions have to do with it. -// (b) SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY: -// This internally forces the NUMBER_OF_UNSHARED_INSTANCES to be -// ignored and start sharing ALL Item derivations instantly. -class InstanceManagerHelper -{ - typedef std::unordered_map<std::size_t, std::pair<sal_uInt16, DefaultItemInstanceManager*>> managerTypeMap; - managerTypeMap maManagerPerType; - -public: - InstanceManagerHelper() {} - ~InstanceManagerHelper() - { - for (auto& rCandidate : maManagerPerType) - if (nullptr != rCandidate.second.second) - delete rCandidate.second.second; - } - - ItemInstanceManager* getOrCreateItemInstanceManager(const SfxPoolItem& rItem) - { - // deactivated? - if (g_bDisableItemInstanceManager) - return nullptr; - - // Item cannot be shared? - if (!rItem.isShareable()) - return nullptr; - - // Prefer getting an ItemInstanceManager directly from - // the Item: These are the extra implemented (and thus - // hopefully fastest) incarnations - ItemInstanceManager* pManager(rItem.getItemInstanceManager()); - - // Check for correct hash, there may be derivations of that class. - // Note that Managers from the Items are *not* added to local list, - // they are expected to be static instances at the Items - const std::size_t aHash(typeid(rItem).hash_code()); - if (nullptr != pManager && pManager->getClassHash() == aHash) - return pManager; - - // check local memory for existing entry - managerTypeMap::iterator aHit(maManagerPerType.find(aHash)); - - // no instance yet - if (aHit == maManagerPerType.end()) - { - // create a default one to start usage-counting - if (g_bShareImmediately) - { - // create, insert locally and immediately start sharing - DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager(aHash)); - maManagerPerType.insert({aHash, std::make_pair(0, pNew)}); - return pNew; - } - - // start countdown from NUMBER_OF_UNSHARED_INSTANCES until zero is reached - maManagerPerType.insert({aHash, std::make_pair(NUMBER_OF_UNSHARED_INSTANCES, nullptr)}); - return nullptr; - } - - // if there is already an ItemInstanceManager incarnated, return it - if (nullptr != aHit->second.second) - return aHit->second.second; - - if (aHit->second.first > 0) - { - // still not the needed number of hits, countdown & return nullptr - aHit->second.first--; - return nullptr; - } - - // here the countdown is zero and there is not yet a ItemInstanceManager - // incarnated. Do so, register and return it - assert(nullptr == aHit->second.second); - DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager(aHash)); - aHit->second.second = pNew; - - return pNew; - } - - ItemInstanceManager* getExistingItemInstanceManager(const SfxPoolItem& rItem) - { - // deactivated? - if (g_bDisableItemInstanceManager) - return nullptr; - - // Item cannot be shared? - if (!rItem.isShareable()) - return nullptr; - - // Prefer getting an ItemInstanceManager directly from - // the Item: These are the extra implemented (and thus - // hopefully fastest) incarnations - ItemInstanceManager* pManager(rItem.getItemInstanceManager()); - - // Check for correct hash, there may be derivations of that class. - // Note that Managers from the Items are *not* added to local list, - // they are expected to be static instances at the Items - const std::size_t aHash(typeid(rItem).hash_code()); - if (nullptr != pManager && pManager->getClassHash() == aHash) - return pManager; - - // check local memory for existing entry - managerTypeMap::iterator aHit(maManagerPerType.find(aHash)); - - if (aHit == maManagerPerType.end()) - // no instance yet, return nullptr - return nullptr; - - // if there is already a ItemInstanceManager incarnated, return it - if (nullptr != aHit->second.second) - return aHit->second.second; - - // count-up needed number of hits again if item is released - if (aHit->second.first < NUMBER_OF_UNSHARED_INSTANCES) - aHit->second.first++; - - return nullptr; - } -}; - -// the single static instance that takes over that global Item sharing -static InstanceManagerHelper aInstanceManagerHelper; - -SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, bool bPassingOwnership) -{ - if (nullptr == pSource) - // SfxItemState::UNKNOWN aka current default (nullptr) - // just use/return nullptr - return nullptr; - - if (pSource->isStaticDefault()) - // static default Items can just be used without RefCounting - // NOTE: This now includes IsInvalidItem/IsDisabledItem - return pSource; - - if (0 == pSource->Which()) - { - // There should be no Items with 0 == WhichID, but there are some - // constructed for dialog return values AKA result (look for SetReturnValue) - // these need to be cloned (currently...) - if (bPassingOwnership) - return pSource; - return pSource->Clone(); - } - - if (pSource->isDynamicDefault() && rPool.GetPoolDefaultItem(pSource->Which()) == pSource) - // dynamic defaults are not allowed to 'leave' the Pool they are - // defined for. We can check by comparing the PoolDefault (the - // PoolDefaultItem) to pSource by ptr compare (instance). When - // same Item we can use without RefCount. Else it will be cloned - // below the standard way. - return pSource; - -#ifdef DBG_UTIL - // remember WhichID due to being able to assert Clone() error(s) - const sal_uInt16 nWhich(pSource->Which()); -#endif - - if (SfxItemPool::IsSlot(pSource->Which())) - { - // SlotItems were always cloned in original (even when bPassingOwnership), - // so do that here, too (but without bPassingOwnership). - // They do not need to be registered at pool (actually impossible, pools - // do not have entries for SlotItems) so handle here early - if (!bPassingOwnership) - { - pSource = pSource->Clone(rPool.GetMasterPool()); - // ARGH! Found out that *some* ::Clone implementations fail to also clone the - // WhichID set at the original Item, e.g. SfxFrameItem. Assert, this is an error -#ifdef DBG_UTIL - assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); -#endif - } - - return pSource; - } - - // get the pool with which ItemSets have to work, plus get the - // pool at which the WhichID is defined, so calls to it do not - // have to do this repeatedly - SfxItemPool* pMasterPool(rPool.GetMasterPool()); - assert(nullptr != pMasterPool); - - // The Item itself is shareable when it is used/added at an instance - // that RefCounts the Item, SfxItemPool or SfxPoolItemHolder. Try - // to share items that are already shared - while(pSource->GetRefCount() > 0) - { - if (!pSource->isShareable()) - // not shareable, done - break; - - // SfxSetItems cannot be shared if they are in/use another pool - if (pSource->isSetItem() && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool) - break; - - // If we get here we can share the Item - pSource->AddRef(); - return pSource; - } - - // try to get an ItemInstanceManager for global Item instance sharing - ItemInstanceManager* pManager(aInstanceManagerHelper.getOrCreateItemInstanceManager(*pSource)); - - // check if we can globally share the Item using an ItemInstanceManager - while (nullptr != pManager) - { - const SfxPoolItem* pAlternative(pManager->find(*pSource)); - if(nullptr == pAlternative) - // no already globally shared one found, done - break; - - // Here we do *not* need to check if it is an SfxSetItem - // and cannot be shared if they are in/use another pool: - // The SfxItemSet::operator== will check for SfxItemPools - // being equal, thus when found in global share the Pool - // cannot be equal - - // need to delete evtl. handed over ownership change Item - if (bPassingOwnership) - delete pSource; - - // If we get here we can share the Item - pAlternative->AddRef(); - return pAlternative; - } - - // check if the handed over and to be directly used item is a - // SfxSetItem, that would make it pool-dependent. It then must have - // the same target-pool, ensure that by the cost of cloning it - // (should not happen) - if (bPassingOwnership - && pSource->isSetItem() - && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool) - { - const SfxPoolItem* pOld(pSource); - pSource = pSource->Clone(pMasterPool); -#ifdef DBG_UTIL - assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); -#endif - delete pOld; - } - -#ifdef DBG_UTIL - // create statistics for listSfxPoolItemsWithHighestUsage - addUsage(*pSource); -#endif - - // when we reach this line we know that we have to add/create a new item. If - // bPassingOwnership is given just use the item, else clone it - if (!bPassingOwnership) - { - pSource = pSource->Clone(pMasterPool); -#ifdef DBG_UTIL - assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)"); -#endif - } - - // increase RefCnt 0->1 - pSource->AddRef(); - - // check if we should register this Item for the global - // ItemInstanceManager mechanism (only for shareable Items) - if (nullptr != pManager) - pManager->add(*pSource); - - return pSource; -} - -void implCleanupItemEntry(const SfxPoolItem* pSource) -{ - if (nullptr == pSource) - // no entry, done - return; - - if (pSource->isStaticDefault()) - // static default Items can just be used without RefCounting - // NOTE: This now includes IsInvalidItem/IsDisabledItem - return; - - if (0 == pSource->Which()) - { - // There should be no Items with 0 == WhichID, but there are some - // constructed for dialog return values AKA result (look for SetReturnValue) - // and need to be deleted - delete pSource; - return; - } - - if (pSource->isDynamicDefault()) - // dynamic default Items can only be used without RefCounting - // when same pool. this is already checked at implCreateItemEntry, - // so it would have been cloned (and would no longer have this - // flag). So we can just return here - return; - - if (SfxItemPool::IsSlot(pSource->Which())) - { - // SlotItems are cloned, so delete - delete pSource; - return; - } - - if (1 < pSource->GetRefCount()) - { - // Still multiple references present, so just alter the RefCount - pSource->ReleaseRef(); - return; - } - - // try to get an ItemInstanceManager for global Item instance sharing - ItemInstanceManager* pManager(aInstanceManagerHelper.getExistingItemInstanceManager(*pSource)); - - // check if we should/can remove this Item from the global - // ItemInstanceManager mechanism - if (nullptr != pManager) - pManager->remove(*pSource); - - // decrease RefCnt before deleting (destructor asserts for it and that's - // good to find other errors) - pSource->ReleaseRef(); - - // delete Item - delete pSource; -} // Delete single Items or all Items (nWhich == 0) sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich ) diff --git a/svl/source/items/poolitem.cxx b/svl/source/items/poolitem.cxx index a9db94057d8a..709d7aa64a83 100644 --- a/svl/source/items/poolitem.cxx +++ b/svl/source/items/poolitem.cxx @@ -513,16 +513,6 @@ const SfxPoolItem* DefaultItemInstanceManager::find(const SfxPoolItem& rItem) co return nullptr; } -void DefaultItemInstanceManager::add(const SfxPoolItem& rItem) -{ - maRegistered[rItem.Which()].insert(&rItem); -} - -void DefaultItemInstanceManager::remove(const SfxPoolItem& rItem) -{ - maRegistered[rItem.Which()].erase(&rItem); -} - ItemInstanceManager* SfxPoolItem::getItemInstanceManager() const { return nullptr; } SfxPoolItem::SfxPoolItem(sal_uInt16 const nWhich, SfxItemType eType) |