summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2024-07-01 12:32:42 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2024-07-01 17:07:35 +0200
commit001d8041aebfaf460bf8420af311e240a9d42183 (patch)
treed85b6565ad22157338c61053d2b24db3a73e303f /svl
parentaf2175bb87b8e8a7184916e110e2b22ec542357d (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.mk1
-rw-r--r--svl/source/items/globalpool.cxx453
-rw-r--r--svl/source/items/itemset.cxx402
-rw-r--r--svl/source/items/poolitem.cxx10
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)