Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  globalpool.cxx   Sprache: C

 
/* -*- 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<SfxItemType, std::pair<sal_uInt16, ItemInstanceManager*>>
        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 SfxItemType, 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 for fastest access
        if (nullptr != pManager && pManager->ItemType() == rItem.ItemType())
            return pManager;

        // check local memory for existing entry
        managerTypeMap::iterator aHit(maManagerPerType.find(rItem.ItemType()));

        // 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
                ItemInstanceManager* pNew;
                if (rItem.supportsHashCode())
                    pNew = new HashedItemInstanceManager(rItem.ItemType());
                else
                    pNew = new DefaultItemInstanceManager(rItem.ItemType());
                maManagerPerType.insert({ rItem.ItemType(), std::make_pair(0, pNew) });
                return pNew;
            }

            // start countdown from NUMBER_OF_UNSHARED_INSTANCES until zero is reached
            maManagerPerType.insert(
                { rItem.ItemType(), 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);
        ItemInstanceManager* pNew;
        if (rItem.supportsHashCode())
            pNew = new HashedItemInstanceManager(rItem.ItemType());
        else
            pNew = new DefaultItemInstanceManager(rItem.ItemType());
        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 SfxItemType, 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
        if (nullptr != pManager && pManager->ItemType() == rItem.ItemType())
            return pManager;

        // check local memory for existing entry
        managerTypeMap::iterator aHit(maManagerPerType.find(rItem.ItemType()));

        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(const 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
    if (pSource->GetRefCount() > 0)
    {
        if (pSource->isShareable())
        {
            // SfxSetItems cannot be shared if they are in/use another pool
            if (!pSource->isSetItem()
                || static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() == pMasterPool)
            {
                // 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
    if (pManager)
    {
        const SfxPoolItem* pAlternative(pManager->find(*pSource));
        if (pAlternative)
        {
            // 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)
    {
        auto pPreviousSource = pSource;
        pSource = pSource->Clone(pMasterPool);
#ifdef DBG_UTIL
        assert(pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID (!)");
#endif
        SAL_WARN_IF(typeid(*pPreviousSource) != typeid(*pSource), "svl",
                    "wrong item from Clone(), expected " << typeid(*pPreviousSource).name()
                                                         << " but got " << typeid(*pSource).name());
        assert(typeid(*pPreviousSource) == typeid(*pSource) && "wrong item from Clone()");
    }

    // 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: */

Messung V0.5
C=85 H=89 G=86

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge