diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2021-06-11 12:07:44 +0200 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2021-06-14 12:46:07 +0200 |
commit | 49b3b9d3391abb50aefe291d2ee0f8bca7eb6bd0 (patch) | |
tree | e75e5ade8acbf8aa3f040aa28ef08572752935ad /svl | |
parent | d376297c643785564e7bda1a74b573c35ade6cb8 (diff) |
Assert on valid order of which ids in ranges on SfxItemSet creation
This allows to make sure we actually use sorted which ranges,
and then it's safe to call SfxItemSet::MergeRange when needed.
Also this change relaxes the previous requirement that ranges
must be separated by at least one; this allows to have adjacent
ranges, like in
RES_FRMATR_BEGIN, RES_FRMATR_END-1,
RES_GRFATR_BEGIN, RES_GRFATR_END-1,
where RES_FRMATR_END is equal to RES_GRFATR_BEGIN. Allowing this
makes possible to (1) self-document the ranges, so it's clear
which ranges are included; and (2) be safe in case when these
constants would change, so that the one merged range would not
unexpectedly contain everything inserted between RES_FRMATR_END
and RES_GRFATR_BEGIN.
Change-Id: Iaad0f099b85059b3aa318a347aa7fbd3f6d455c7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116909
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 8aaa28ed43978a9a4a20d62368410a57ec05c23f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117114
Diffstat (limited to 'svl')
-rw-r--r-- | svl/source/inc/items_helper.hxx | 126 | ||||
-rw-r--r-- | svl/source/items/itempool.cxx | 20 | ||||
-rw-r--r-- | svl/source/items/itemset.cxx | 371 |
3 files changed, 172 insertions, 345 deletions
diff --git a/svl/source/inc/items_helper.hxx b/svl/source/inc/items_helper.hxx new file mode 100644 index 000000000000..75582d9f8741 --- /dev/null +++ b/svl/source/inc/items_helper.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <sal/config.h> + +#include <sal/types.h> +#include <svl/itemset.hxx> + +#include <memory> +#include <utility> +#include <vector> + +namespace svl::detail +{ +/** + * Determines the number of sal_uInt16s in a 0-terminated array of pairs of + * sal_uInt16s, each representing a range of sal_uInt16s, and total capacity of the ranges. + * The terminating 0 is included in the count. + */ +inline std::pair<sal_uInt16, sal_uInt16> CountRanges(const sal_uInt16* pRanges) +{ + sal_uInt16 nCount = 0; + sal_uInt16 nCapacity = 0; + if (pRanges) + { + nCount = 1; + while (*pRanges) + { + nCount += 2; + nCapacity += rangeSize(pRanges[0], pRanges[1]); + pRanges += 2; + } + } + return { nCount, nCapacity }; +} + +// Adds a range to which ranges, keeping the ranges in valid state (sorted, non-overlapping) +inline std::unique_ptr<sal_uInt16[]> MergeRange(const sal_uInt16* pWhichRanges, sal_uInt16 nFrom, + sal_uInt16 nTo) +{ + assert(validRange(nFrom, nTo)); + + if (!pWhichRanges) + { + auto pNewRanges = std::make_unique<sal_uInt16[]>(3); + pNewRanges[0] = nFrom; + pNewRanges[1] = nTo; + pNewRanges[2] = 0; + return pNewRanges; + } + + assert(validRanges(pWhichRanges)); + + // create vector of ranges (sal_uInt16 pairs of lower and upper bound) + const size_t nOldCount = CountRanges(pWhichRanges).first; + std::vector<std::pair<sal_uInt16, sal_uInt16>> aRangesTable; + aRangesTable.reserve(nOldCount / 2 + 1); + bool bAdded = false; + for (size_t i = 0; i + 1 < nOldCount; i += 2) + { + if (!bAdded && pWhichRanges[i] >= nFrom) + { // insert new range, keep ranges sorted + aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); + bAdded = true; + } + // insert current range + aRangesTable.emplace_back( + std::pair<sal_uInt16, sal_uInt16>(pWhichRanges[i], pWhichRanges[i + 1])); + } + if (!bAdded) + aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); + + // true if ranges overlap or adjoin, false if ranges are separate + auto needMerge + = [](std::pair<sal_uInt16, sal_uInt16> lhs, std::pair<sal_uInt16, sal_uInt16> rhs) { + return (lhs.first - 1) <= rhs.second && (rhs.first - 1) <= lhs.second; + }; + + auto it = aRangesTable.begin(); + // we got at least one range + for (;;) + { + auto itNext = std::next(it); + if (itNext == aRangesTable.end()) + break; + // check neighbouring ranges, find first range which overlaps or adjoins a previous range + if (needMerge(*it, *itNext)) + { + // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first) + it->second = std::max(it->second, itNext->second); + aRangesTable.erase(itNext); + } + else + ++it; + } + + // construct range array + const size_t nNewSize = 2 * aRangesTable.size() + 1; + auto pNewRanges = std::make_unique<sal_uInt16[]>(nNewSize); + for (size_t i = 0; i < (nNewSize - 1); i += 2) + std::tie(pNewRanges[i], pNewRanges[i + 1]) = aRangesTable[i / 2]; + + pNewRanges[nNewSize - 1] = 0; + return pNewRanges; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx index 32d7744b1837..99e0949e38df 100644 --- a/svl/source/items/itempool.cxx +++ b/svl/source/items/itempool.cxx @@ -27,6 +27,8 @@ #include <svl/SfxBroadcaster.hxx> #include <svl/hint.hxx> #include <svl/itemset.hxx> + +#include <items_helper.hxx> #include <poolio.hxx> #include <cassert> @@ -771,20 +773,12 @@ void SfxItemPool::FillItemIdRanges_Impl( std::unique_ptr<sal_uInt16[]>& pWhichRa { DBG_ASSERT( !pImpl->mpPoolRanges, "GetFrozenRanges() would be faster!" ); - const SfxItemPool *pPool; - sal_uInt16 nLevel = 0; - for( pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get() ) - ++nLevel; - - pWhichRanges.reset(new sal_uInt16[ 2*nLevel + 1 ]); + pWhichRanges.reset(); - nLevel = 0; - for( pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get() ) - { - pWhichRanges[nLevel++] = pPool->pImpl->mnStart; - pWhichRanges[nLevel++] = pPool->pImpl->mnEnd; - pWhichRanges[nLevel] = 0; - } + // Merge all ranges, keeping them sorted + for (const SfxItemPool* pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get()) + pWhichRanges = svl::detail::MergeRange(pWhichRanges.get(), pPool->pImpl->mnStart, + pPool->pImpl->mnEnd); } const sal_uInt16* SfxItemPool::GetFrozenIdRanges() const diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx index 9ae951ab5936..3324f69e6122 100644 --- a/svl/source/items/itemset.cxx +++ b/svl/source/items/itemset.cxx @@ -32,47 +32,7 @@ #include <svl/itemiter.hxx> #include <svl/whiter.hxx> -const sal_uInt16 nInitCount = 10; // Single USHORTs => 5 pairs without '0' - -namespace -{ - -/** - * Determines the number of sal_uInt16s in a 0-terminated array of pairs of - * sal_uInt16s. - * The terminating 0 is not included in the count. - */ -sal_uInt16 Count_Impl( const sal_uInt16 *pRanges ) -{ - sal_uInt16 nCount = 0; - while ( *pRanges ) - { - nCount += 2; - pRanges += 2; - } - return nCount; -} - -/** - * Determines the total number of sal_uInt16s described in a 0-terminated - * array of pairs of sal_uInt16s, each representing a range of sal_uInt16s. - */ -sal_uInt16 Capacity_Impl( const sal_uInt16 *pRanges ) -{ - sal_uInt16 nCount = 0; - - if ( pRanges ) - { - while ( *pRanges ) - { - nCount += pRanges[1] - pRanges[0] + 1; - pRanges += 2; - } - } - return nCount; -} - -} +#include <items_helper.hxx> /** * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to @@ -94,26 +54,20 @@ SfxItemSet::SfxItemSet(SfxItemPool& rPool) m_pPool->FillItemIdRanges_Impl(tmp); m_pWhichRanges = tmp.release(); } + assert(svl::detail::validRanges(m_pWhichRanges)); const sal_uInt16 nSize = TotalCount(); m_pItems.reset(new const SfxPoolItem*[nSize]{}); } -void SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable) +sal_uInt16 SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable) { - sal_uInt16 nCnt = 0; - const sal_uInt16* pPtr = pWhichPairTable; - while( *pPtr ) - { - nCnt += ( *(pPtr+1) - *pPtr ) + 1; - pPtr += 2; - } - - m_pItems.reset( new const SfxPoolItem*[nCnt]{} ); - - std::ptrdiff_t cnt = pPtr - pWhichPairTable +1; - m_pWhichRanges = new sal_uInt16[ cnt ]; - memcpy( m_pWhichRanges, pWhichPairTable, sizeof( sal_uInt16 ) * cnt ); + const auto& [nCnt, nCap] = svl::detail::CountRanges(pWhichPairTable); + m_pItems.reset(new const SfxPoolItem* [nCap] {}); + m_pWhichRanges = new sal_uInt16[nCnt]; + memcpy(m_pWhichRanges, pWhichPairTable, sizeof(sal_uInt16) * nCnt); + assert(svl::detail::validRanges(m_pWhichRanges)); + return nCap; } SfxItemSet::SfxItemSet( @@ -132,6 +86,7 @@ SfxItemSet::SfxItemSet( assert(wids.size() % 2 == 0); std::copy(wids.begin(), wids.end(), m_pWhichRanges); m_pWhichRanges[wids.size()] = 0; + assert(svl::detail::validRanges(m_pWhichRanges)); } SfxItemSet::SfxItemSet( @@ -143,22 +98,15 @@ SfxItemSet::SfxItemSet( assert(wids.size() != 0); std::size_t i = 0; std::size_t size = 0; -#if !defined NDEBUG - //TODO: sal_uInt16 prev = 0; -#endif for (auto const & p: wids) { - assert(svl::detail::validRange(p.wid1, p.wid2)); - //TODO: assert(prev == 0 || svl::detail::validGap(prev, p.wid1)); m_pWhichRanges[i++] = p.wid1; m_pWhichRanges[i++] = p.wid2; size += svl::detail::rangeSize(p.wid1, p.wid2); // cannot overflow, assuming std::size_t is no smaller than // sal_uInt16 -#if !defined NDEBUG - //TODO: prev = p.wid2; -#endif } m_pWhichRanges[i] = 0; + assert(svl::detail::validRanges(m_pWhichRanges)); m_pItems.reset( new SfxPoolItem const *[size]{} ); } @@ -178,16 +126,13 @@ SfxItemSet::SfxItemSet( const SfxItemSet& rASet ) , m_pParent( rASet.m_pParent ) , m_nCount( rASet.m_nCount ) { - // Calculate the attribute count - sal_uInt16 nCnt = 0; - sal_uInt16* pPtr = rASet.m_pWhichRanges; - while( *pPtr ) + if (!rASet.m_pWhichRanges) { - nCnt += ( *(pPtr+1) - *pPtr ) + 1; - pPtr += 2; + m_pWhichRanges = nullptr; + return; } - m_pItems.reset( new const SfxPoolItem* [ nCnt ] ); + sal_uInt16 nCnt = InitRanges_Impl(rASet.m_pWhichRanges); // Copy attributes SfxPoolItem const** ppDst = m_pItems.get(); @@ -210,10 +155,7 @@ SfxItemSet::SfxItemSet( const SfxItemSet& rASet ) // !IsPoolable() => assign via Pool *ppDst = &m_pPool->Put( **ppSrc ); - // Copy the WhichRanges - std::ptrdiff_t cnt = pPtr - rASet.m_pWhichRanges+1; - m_pWhichRanges = new sal_uInt16[ cnt ]; - memcpy( m_pWhichRanges, rASet.m_pWhichRanges, sizeof( sal_uInt16 ) * cnt); + assert(svl::detail::validRanges(m_pWhichRanges)); } SfxItemSet::SfxItemSet(SfxItemSet&& rASet) noexcept @@ -227,6 +169,7 @@ SfxItemSet::SfxItemSet(SfxItemSet&& rASet) noexcept rASet.m_pParent = nullptr; rASet.m_pWhichRanges = nullptr; rASet.m_nCount = 0; + assert(svl::detail::validRanges(m_pWhichRanges)); } SfxItemSet::~SfxItemSet() @@ -664,67 +607,8 @@ void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo ) eItemState == SfxItemState::DEFAULT || eItemState == SfxItemState::SET) return; -#ifdef DBG_UTIL - assert(nFrom <= nTo); - for (const sal_uInt16 *pRange = m_pWhichRanges; *pRange; pRange += 2) - { - assert(pRange[0] <= pRange[1]); - // ranges must be sorted and discrete - assert( - !pRange[2] || (pRange[2] > pRange[1] && pRange[2] - pRange[1] > 1)); - } -#endif - - // create vector of ranges (sal_uInt16 pairs of lower and upper bound) - const size_t nOldCount = Count_Impl(m_pWhichRanges); - std::vector<std::pair<sal_uInt16, sal_uInt16>> aRangesTable; - aRangesTable.reserve(nOldCount/2 + 1); - bool bAdded = false; - for (size_t i = 0; i < nOldCount; i += 2) - { - if (!bAdded && m_pWhichRanges[i] >= nFrom) - { // insert new range, keep ranges sorted - aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); - bAdded = true; - } - // insert current range - aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(m_pWhichRanges[i], m_pWhichRanges[i+1])); - } - if (!bAdded) - aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); - - // true if ranges overlap or adjoin, false if ranges are separate - auto needMerge = [](std::pair<sal_uInt16, sal_uInt16> lhs, std::pair<sal_uInt16, sal_uInt16> rhs) - {return (lhs.first-1) <= rhs.second && (rhs.first-1) <= lhs.second;}; - - std::vector<std::pair<sal_uInt16, sal_uInt16> >::iterator it = aRangesTable.begin(); - // we got at least one range - for (;;) - { - auto itNext = std::next(it); - if (itNext == aRangesTable.end()) - break; - // check neighbouring ranges, find first range which overlaps or adjoins a previous range - if (needMerge(*it, *itNext)) - { - // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first) - it->second = std::max(it->second, itNext->second); - aRangesTable.erase(itNext); - } - else - ++it; - } - - // construct range array - const size_t nNewSize = 2 * aRangesTable.size() + 1; - std::vector<sal_uInt16> aRanges(nNewSize); - for (size_t i = 0; i < (nNewSize - 1); i +=2) - std::tie(aRanges[i], aRanges[i+1]) = aRangesTable[i/2]; - - // null terminate to be compatible with sal_uInt16* array pointers - aRanges.back() = 0; - - SetRanges( aRanges.data() ); + auto pNewRanges = svl::detail::MergeRange(m_pWhichRanges, nFrom, nTo); + SetRanges(pNewRanges.get()); } /** @@ -736,18 +620,21 @@ void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges ) // Identical Ranges? if (m_pWhichRanges == pNewRanges) return; - const sal_uInt16* pOld = m_pWhichRanges; - const sal_uInt16* pNew = pNewRanges; - while ( *pOld == *pNew ) + if (m_pWhichRanges) { - if ( !*pOld && !*pNew ) - return; - ++pOld; - ++pNew; + const sal_uInt16* pOld = m_pWhichRanges; + const sal_uInt16* pNew = pNewRanges; + while (*pOld == *pNew) + { + if (!*pOld && !*pNew) + return; + ++pOld; + ++pNew; + } } // create new item-array (by iterating through all new ranges) - sal_uInt16 nSize = Capacity_Impl(pNewRanges); + const auto& [nCount, nSize] = svl::detail::CountRanges(pNewRanges); SfxPoolItem const** aNewItems = new const SfxPoolItem* [ nSize ]; sal_uInt16 nNewCount = 0; if (m_nCount == 0) @@ -807,12 +694,12 @@ void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges ) } else { - sal_uInt16 nCount = Count_Impl(pNewRanges) + 1; if (m_pWhichRanges != m_pPool->GetFrozenIdRanges()) delete[] m_pWhichRanges; m_pWhichRanges = new sal_uInt16[ nCount ]; memcpy( m_pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount ); } + assert(svl::detail::validRanges(m_pWhichRanges)); } /** @@ -907,7 +794,7 @@ const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const { if( IsInvalidItem(*ppFnd) ) { //FIXME: The following code is duplicated further down - SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich); + assert(m_pPool); //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich); //!return aDefault; return m_pPool->GetDefaultItem( nWhich ); @@ -934,9 +821,8 @@ const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const } while (nullptr != pCurrentSet); // Get the Default from the Pool and return - SAL_WARN_IF(!m_pPool, "svl.items", "no Pool, but status is ambiguous, with ID/pos " << nWhich); - const SfxPoolItem *pItem = &m_pPool->GetDefaultItem( nWhich ); - return *pItem; + assert(m_pPool); + return m_pPool->GetDefaultItem( nWhich ); } /** @@ -1549,19 +1435,12 @@ void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter) const // ----------------------------------------------- class SfxAllItemSet SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool ) -: SfxItemSet(rPool, nullptr), - nFree(nInitCount) +: SfxItemSet(rPool, nullptr) { - // Initially no Items - m_pItems = nullptr; - - // Allocate nInitCount pairs at USHORTs for Ranges - m_pWhichRanges = new sal_uInt16[nInitCount + 1]{}; } SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy) -: SfxItemSet(rCopy), - nFree(0) +: SfxItemSet(rCopy) { } @@ -1570,66 +1449,8 @@ SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy) * The compiler does not take the ctor with the 'const SfxItemSet&'! */ SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy) -: SfxItemSet(rCopy), - nFree(0) -{ -} - -/** - * This internal function creates a new WhichRanges array, which is copied - * from the 'nOldSize'-USHORTs long 'pUS'. It has new USHORTs at the end instead - * of 'nIncr'. - * The terminating sal_uInt16 with the '0' is neither accounted for in 'nOldSize' - * nor in 'nIncr', but always explicitly added. - * - * @returns the new WhichRanges array (the old 'pUS' is freed) - */ -static sal_uInt16 *AddRanges_Impl( - sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr) +: SfxItemSet(rCopy) { - // Create new WhichRanges array - sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ]; - - // Take over the old Ranges - memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) ); - - // Initialize the new one to 0 - memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) ); - - // Free the old array - delete[] pUS; - - return pNew; -} - -/** - * This internal function creates a new ItemArray, which is copied from 'pItems', - * but has room for a new ItemPointer at 'nPos'. - * - * @returns the new ItemArray (the old 'pItems' is freed) - */ -static void AddItem_Impl(std::unique_ptr<SfxPoolItem const*[]> & rpItems, sal_uInt16 nOldSize, sal_uInt16 nPos) -{ - // Create new ItemArray - SfxPoolItem const** pNew = new const SfxPoolItem*[nOldSize+1]; - - // Was there one before? - if ( rpItems ) - { - // Copy all Items before nPos - if ( nPos ) - memcpy( static_cast<void*>(pNew), rpItems.get(), nPos * sizeof(SfxPoolItem *) ); - - // Copy all Items after nPos - if ( nPos < nOldSize ) - memcpy( static_cast<void*>(pNew + nPos + 1), rpItems.get() + nPos, - (nOldSize-nPos) * sizeof(SfxPoolItem *) ); - } - - // Initialize new Item - *(pNew + nPos) = nullptr; - - rpItems.reset(pNew); } /** @@ -1637,122 +1458,8 @@ static void AddItem_Impl(std::unique_ptr<SfxPoolItem const*[]> & rpItems, sal_uI */ const SfxPoolItem* SfxAllItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership ) { - sal_uInt16 nPos = 0; // Position for 'rItem' in 'm_pItems' - const sal_uInt16 nItemCount = TotalCount(); - - // Let's see first whether there's a suitable Range already - sal_uInt16 *pPtr = m_pWhichRanges; - while ( *pPtr ) - { - // WhichId is within this Range? - if( *pPtr <= nWhich && nWhich <= *(pPtr+1) ) - { - // Insert - nPos += nWhich - *pPtr; - break; - } - - // Carry over the position of the Item in m_pItems - nPos += *(pPtr+1) - *pPtr + 1; - - // To the next Range - pPtr += 2; - } - - // WhichId not yet present? - if ( !*pPtr ) - { - // Let's see if we can attach it somewhere - pPtr = m_pWhichRanges; - nPos = 0; - while ( *pPtr ) - { - // WhichId is right before this Range? - if ( (nWhich+1) == *pPtr ) - { - // Range grows downwards - (*pPtr)--; - - // Make room before first Item of this Range - AddItem_Impl(m_pItems, nItemCount, nPos); - break; - } - - // WhichId is right after this Range? - else if ( (nWhich-1) == *(pPtr+1) ) - { - // Range grows upwards? - (*(pPtr+1))++; - - // Make room after last Item of this Range - nPos += nWhich - *pPtr; - AddItem_Impl(m_pItems, nItemCount, nPos); - break; - } - - // Carry over position of the Item in m_pItems - nPos += *(pPtr+1) - *pPtr + 1; - - // To the next Range - pPtr += 2; - } - } - - // No extensible Range found? - if ( !*pPtr ) - { - // No room left in m_pWhichRanges? => Expand! - std::ptrdiff_t nSize = pPtr - m_pWhichRanges; - if( !nFree ) - { - m_pWhichRanges = AddRanges_Impl(m_pWhichRanges, nSize, nInitCount); - nFree += nInitCount; - } - - // Attach new WhichRange - pPtr = m_pWhichRanges + nSize; - *pPtr++ = nWhich; - *pPtr = nWhich; - nFree -= 2; - - // Expand ItemArray - nPos = nItemCount; - AddItem_Impl(m_pItems, nItemCount, nPos); - } - - // Add new Item to Pool - const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership ); - - // Remember old Item - bool bIncrementCount = false; - const SfxPoolItem* pOld = m_pItems[nPos]; - if ( IsInvalidItem(pOld) ) // state "dontcare" - pOld = nullptr; - if ( !pOld ) - { - bIncrementCount = true; - pOld = m_pParent - ? &m_pParent->Get( nWhich ) - : (SfxItemPool::IsWhich(nWhich) - ? &m_pPool->GetDefaultItem(nWhich) - : nullptr); - } - - // Add new Item to ItemSet - m_pItems[nPos] = &rNew; - - // Send Changed Notification - if ( pOld ) - { - Changed( *pOld, rNew ); - if ( !IsDefaultItem(pOld) ) - m_pPool->Remove( *pOld ); - } - - if ( bIncrementCount ) - ++m_nCount; - - return &rNew; + MergeRange(nWhich, nWhich); + return SfxItemSet::PutImpl(rItem, nWhich, bPassingOwnership); } /** |