Add 'reference' to the iterator_traits, needed by LegacyIterator reqs
[LibreOffice.git] / svl / source / items / itemset.cxx
blob04fab3c9306e551d8136ec50163c45aa326187a2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <string.h>
23 #include <algorithm>
24 #include <cassert>
25 #include <cstddef>
27 #include <libxml/xmlwriter.h>
29 #include <sal/log.hxx>
30 #include <svl/itemset.hxx>
31 #include <svl/itempool.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svl/setitem.hxx>
34 #include <svl/whiter.hxx>
36 #include <items_helper.hxx>
38 /**
39 * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to
40 * the supplied SfxItemPool.
42 * For Sfx programmers: an SfxItemSet constructed in this way cannot
43 * contain any Items with SlotIds as Which values.
45 * Don't create ItemSets with full range before FreezeIdRanges()!
47 SfxItemSet::SfxItemSet(SfxItemPool& rPool)
48 : SfxItemSet(rPool, rPool.GetFrozenIdRanges())
52 SfxItemSet::SfxItemSet( SfxItemPool& rPool, SfxAllItemSetFlag )
53 : m_pPool(&rPool)
54 , m_pParent(nullptr)
55 , m_ppItems(nullptr)
56 , m_nCount(0)
57 , m_bItemsFixed(false)
61 /** special constructor for SfxItemSetFixed */
62 SfxItemSet::SfxItemSet( SfxItemPool& rPool, WhichRangesContainer&& ranges, SfxPoolItem const ** ppItems )
63 : m_pPool(&rPool)
64 , m_pParent(nullptr)
65 , m_ppItems(ppItems)
66 , m_pWhichRanges(std::move(ranges))
67 , m_nCount(0)
68 , m_bItemsFixed(true)
70 assert(ppItems);
71 assert(m_pWhichRanges.size() > 0);
72 assert(svl::detail::validRanges2(m_pWhichRanges));
75 SfxItemSet::SfxItemSet(
76 SfxItemPool & pool,
77 const WhichRangesContainer& wids,
78 std::size_t items):
79 m_pPool(&pool), m_pParent(nullptr),
80 m_ppItems(new SfxPoolItem const *[items]{}),
81 m_pWhichRanges(wids),
82 m_nCount(0),
83 m_bItemsFixed(false)
85 assert(wids.size() != 0);
86 assert(svl::detail::validRanges2(m_pWhichRanges));
89 SfxItemSet::SfxItemSet(SfxItemPool& pool, const WhichRangesContainer& wids)
90 : SfxItemSet(pool, wids, svl::detail::CountRanges(wids))
94 SfxItemSet::SfxItemSet(SfxItemPool& pool, WhichRangesContainer&& wids)
95 : SfxItemSet(pool, wids, svl::detail::CountRanges(wids))
99 SfxItemSet::SfxItemSet( const SfxItemSet& rASet )
100 : m_pPool( rASet.m_pPool )
101 , m_pParent( rASet.m_pParent )
102 , m_pWhichRanges( rASet.m_pWhichRanges )
103 , m_nCount( rASet.m_nCount )
104 , m_bItemsFixed(false)
106 if (rASet.m_pWhichRanges.empty())
108 m_ppItems = nullptr;
109 return;
112 auto nCnt = svl::detail::CountRanges(m_pWhichRanges);
113 m_ppItems = new const SfxPoolItem* [nCnt] {};
115 // Copy attributes
116 SfxPoolItem const** ppDst = m_ppItems;
117 SfxPoolItem const** ppSrc = rASet.m_ppItems;
118 for( sal_uInt16 n = nCnt; n; --n, ++ppDst, ++ppSrc )
119 if ( nullptr == *ppSrc || // Current Default?
120 IsInvalidItem(*ppSrc) || // DontCare?
121 IsStaticDefaultItem(*ppSrc) ) // Defaults that are not to be pooled?
122 // Just copy the pointer
123 *ppDst = *ppSrc;
124 else if (m_pPool->IsItemPoolable( **ppSrc ))
126 // Just copy the pointer and increase RefCount
127 *ppDst = *ppSrc;
128 (*ppDst)->AddRef();
130 else if ( !(*ppSrc)->Which() )
131 *ppDst = (*ppSrc)->Clone();
132 else
133 // !IsPoolable() => assign via Pool
134 *ppDst = &m_pPool->Put( **ppSrc );
136 assert(svl::detail::validRanges2(m_pWhichRanges));
139 SfxItemSet::SfxItemSet(SfxItemSet&& rASet) noexcept
140 : m_pPool( rASet.m_pPool )
141 , m_pParent( rASet.m_pParent )
142 , m_ppItems( rASet.m_ppItems )
143 , m_pWhichRanges( std::move(rASet.m_pWhichRanges) )
144 , m_nCount( rASet.m_nCount )
145 , m_bItemsFixed(false)
147 if (rASet.m_bItemsFixed)
149 // have to make a copy
150 int noItems = svl::detail::CountRanges(m_pWhichRanges);
151 m_ppItems = new const SfxPoolItem* [noItems];
152 std::copy(rASet.m_ppItems, rASet.m_ppItems + noItems, m_ppItems);
154 else
155 // taking over ownership
156 rASet.m_ppItems = nullptr;
157 rASet.m_pPool = nullptr;
158 rASet.m_pParent = nullptr;
159 rASet.m_nCount = 0;
160 assert(svl::detail::validRanges2(m_pWhichRanges));
163 SfxItemSet::~SfxItemSet()
165 if (!m_pWhichRanges.empty()) // might be nullptr if we have been moved-from
167 sal_uInt16 nCount = TotalCount();
168 if( Count() )
170 SfxPoolItem const** ppFnd = m_ppItems;
171 for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
172 if( *ppFnd && !IsInvalidItem(*ppFnd) )
174 if( !(*ppFnd)->Which() )
175 delete *ppFnd;
176 else {
177 // Still multiple references present, so just alter the RefCount
178 if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
179 (*ppFnd)->ReleaseRef();
180 else
181 if ( !IsDefaultItem(*ppFnd) )
182 // Delete from Pool
183 m_pPool->Remove( **ppFnd );
189 if (!m_bItemsFixed)
190 delete[] m_ppItems;
191 m_pWhichRanges.reset(); // for invariant-testing
195 * Delete single Items or all Items (nWhich == 0)
197 sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )
199 if( !Count() )
200 return 0;
202 sal_uInt16 nDel = 0;
203 SfxPoolItem const** ppFnd = m_ppItems;
205 if( nWhich )
207 for (const WhichPair& rPair : m_pWhichRanges)
209 // Within this range?
210 if( rPair.first <= nWhich && nWhich <= rPair.second )
212 // Actually set?
213 ppFnd += nWhich - rPair.first;
214 if( *ppFnd )
216 // Due to the assertions in the sub calls, we need to do the following
217 --m_nCount;
218 const SfxPoolItem *pItemToClear = *ppFnd;
219 *ppFnd = nullptr;
221 if ( !IsInvalidItem(pItemToClear) )
223 if (SfxItemPool::IsWhich(nWhich))
225 const SfxPoolItem& rNew = m_pParent
226 ? m_pParent->Get( nWhich )
227 : m_pPool->GetDefaultItem( nWhich );
229 Changed( *pItemToClear, rNew );
231 if ( pItemToClear->Which() )
232 m_pPool->Remove( *pItemToClear );
234 ++nDel;
237 // found => break
238 break;
240 ppFnd += rPair.second - rPair.first + 1;
243 else
245 nDel = m_nCount;
247 for (const WhichPair& rPair : m_pWhichRanges)
249 for( nWhich = rPair.first; nWhich <= rPair.second; ++nWhich, ++ppFnd )
250 if( *ppFnd )
252 // Due to the assertions in the sub calls, we need to do this
253 --m_nCount;
254 const SfxPoolItem *pItemToClear = *ppFnd;
255 *ppFnd = nullptr;
257 if ( !IsInvalidItem(pItemToClear) )
259 if (SfxItemPool::IsWhich(nWhich))
261 const SfxPoolItem& rNew = m_pParent
262 ? m_pParent->Get( nWhich )
263 : m_pPool->GetDefaultItem( nWhich );
265 Changed( *pItemToClear, rNew );
268 // #i32448#
269 // Take care of disabled items, too.
270 if (!pItemToClear->m_nWhich)
272 // item is disabled, delete it
273 delete pItemToClear;
275 else
277 // remove item from pool
278 m_pPool->Remove( *pItemToClear );
284 return nDel;
287 void SfxItemSet::ClearInvalidItems()
289 SfxPoolItem const** ppFnd = m_ppItems;
290 for (const WhichPair& rPair : m_pWhichRanges)
292 for( sal_uInt16 nWhich = rPair.first; nWhich <= rPair.second; ++nWhich, ++ppFnd )
293 if( IsInvalidItem(*ppFnd) )
295 *ppFnd = nullptr;
296 --m_nCount;
301 void SfxItemSet::InvalidateAllItems()
303 assert( !m_nCount && "There are still Items set" );
304 m_nCount = TotalCount();
305 memset(static_cast<void*>(m_ppItems), -1, m_nCount * sizeof(SfxPoolItem*));
308 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
309 bool bSrchInParent,
310 const SfxPoolItem **ppItem ) const
312 // Find the range in which the Which is located
313 const SfxItemSet* pCurrentSet = this;
314 SfxItemState eRet = SfxItemState::UNKNOWN;
317 SfxPoolItem const** ppFnd = pCurrentSet->m_ppItems;
318 for (const WhichPair& rPair : pCurrentSet->m_pWhichRanges)
320 if ( rPair.first <= nWhich && nWhich <= rPair.second )
322 // Within this range
323 ppFnd += nWhich - rPair.first;
324 if ( !*ppFnd )
326 eRet = SfxItemState::DEFAULT;
327 if( !bSrchInParent )
328 return eRet; // Not present
329 break; // Keep searching in the parents!
332 if ( IsInvalidItem(*ppFnd) )
333 // Different ones are present
334 return SfxItemState::DONTCARE;
336 if ( (*ppFnd)->IsVoidItem() )
337 return SfxItemState::DISABLED;
339 if (ppItem)
341 *ppItem = *ppFnd;
343 return SfxItemState::SET;
345 ppFnd += rPair.second - rPair.first + 1;
347 if (!bSrchInParent)
348 break;
349 pCurrentSet = pCurrentSet->m_pParent;
350 } while (nullptr != pCurrentSet);
351 return eRet;
354 bool SfxItemSet::HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem) const
356 bool bRet = SfxItemState::SET == GetItemState(nWhich, true, ppItem);
357 if (!bRet && ppItem)
358 *ppItem = nullptr;
359 return bRet;
362 const SfxPoolItem* SfxItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
364 if ( !nWhich )
366 assert(!bPassingOwnership);
367 return nullptr; //FIXME: Only because of Outliner bug
370 SfxPoolItem const** ppFnd = m_ppItems;
371 for (const WhichPair& rPair : m_pWhichRanges)
373 if( rPair.first <= nWhich && nWhich <= rPair.second )
375 // Within this range
376 ppFnd += nWhich - rPair.first;
377 if( *ppFnd ) // Already one present
379 // Same Item already present?
380 if ( *ppFnd == &rItem )
382 assert(!bPassingOwnership);
383 return nullptr;
386 // Will 'dontcare' or 'disabled' be overwritten with some real value?
387 if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
389 auto const old = *ppFnd;
390 *ppFnd = &m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
391 if (!IsInvalidItem(old)) {
392 assert(old->Which() == 0);
393 delete old;
395 return *ppFnd;
398 // Turns into disabled?
399 if( !rItem.Which() )
401 if (IsInvalidItem(*ppFnd) || (*ppFnd)->Which() != 0) {
402 *ppFnd = rItem.Clone(m_pPool);
404 if (bPassingOwnership)
405 delete &rItem;
406 return nullptr;
408 else
410 // Same value already present?
411 if ( rItem == **ppFnd )
413 if (bPassingOwnership)
414 delete &rItem;
415 return nullptr;
418 // Add the new one, remove the old one
419 const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
420 const SfxPoolItem* pOld = *ppFnd;
421 *ppFnd = &rNew;
422 if (SfxItemPool::IsWhich(nWhich))
423 Changed( *pOld, rNew );
424 m_pPool->Remove( *pOld );
427 else
429 ++m_nCount;
430 if( !rItem.Which() )
432 *ppFnd = rItem.Clone(m_pPool);
433 if (bPassingOwnership)
434 delete &rItem;
436 else
438 const SfxPoolItem& rNew = m_pPool->PutImpl( rItem, nWhich, bPassingOwnership );
439 *ppFnd = &rNew;
440 if (SfxItemPool::IsWhich(nWhich))
442 const SfxPoolItem& rOld = m_pParent
443 ? m_pParent->Get( nWhich )
444 : m_pPool->GetDefaultItem( nWhich );
445 Changed( rOld, rNew );
449 SAL_WARN_IF(!bPassingOwnership && m_pPool->IsItemPoolable(nWhich) &&
450 dynamic_cast<const SfxSetItem*>( &rItem ) == nullptr &&
451 **ppFnd != rItem,
452 "svl.items", "putted Item unequal, with ID/pos " << nWhich );
453 return *ppFnd;
455 ppFnd += rPair.second - rPair.first + 1;
457 if (bPassingOwnership)
458 delete &rItem;
459 return nullptr;
462 bool SfxItemSet::Put( const SfxItemSet& rSet, bool bInvalidAsDefault )
464 bool bRet = false;
465 if( rSet.Count() )
467 SfxPoolItem const** ppFnd = rSet.m_ppItems;
468 for (const WhichPair& rPair : rSet.m_pWhichRanges)
470 for ( sal_uInt16 nWhich = rPair.first; nWhich <= rPair.second; ++nWhich, ++ppFnd )
471 if( *ppFnd )
473 if ( IsInvalidItem( *ppFnd ) )
475 if ( bInvalidAsDefault )
476 bRet |= 0 != ClearItem( nWhich );
477 // FIXME: Caused a SEGFAULT on non Windows-platforms:
478 // bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
479 else
480 InvalidateItem( nWhich );
482 else
483 bRet |= nullptr != Put( **ppFnd, nWhich );
487 return bRet;
491 * This method takes the Items from the 'rSet' and adds to '*this'.
492 * Which ranges in '*this' that are non-existent in 'rSet' will not
493 * be altered. The Which range of '*this' is also not changed.
495 * Items set in 'rSet' are also set in '*this'.
496 * Default (0 pointer) and Invalid (-1 pointer) Items are processed
497 * according to their parameter 'eDontCareAs' and 'eDefaultAs':
499 * SfxItemState::SET: Hard set to the default of the Pool
500 * SfxItemState::DEFAULT: Deleted (0 pointer)
501 * SfxItemState::DONTCARE: Invalid (-1 pointer)
503 * NB: All other values for 'eDontCareAs' and 'eDefaultAs' are invalid
505 void SfxItemSet::PutExtended
507 const SfxItemSet& rSet, // Source of the Items to be put
508 SfxItemState eDontCareAs, // What will happen to the DontCare Items
509 SfxItemState eDefaultAs // What will happen to the Default Items
512 // don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
513 SfxPoolItem const** ppFnd = rSet.m_ppItems;
514 for (const WhichPair& rPair : rSet.m_pWhichRanges)
516 for ( sal_uInt16 nWhich = rPair.first; nWhich <= rPair.second; ++nWhich, ++ppFnd )
517 if( *ppFnd )
519 if ( IsInvalidItem( *ppFnd ) )
521 // Item is DontCare:
522 switch ( eDontCareAs )
524 case SfxItemState::SET:
525 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
526 break;
528 case SfxItemState::DEFAULT:
529 ClearItem( nWhich );
530 break;
532 case SfxItemState::DONTCARE:
533 InvalidateItem( nWhich );
534 break;
536 default:
537 assert(!"invalid Argument for eDontCareAs");
540 else
541 // Item is set:
542 Put( **ppFnd, nWhich );
544 else
546 // Item is default:
547 switch ( eDefaultAs )
549 case SfxItemState::SET:
550 Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
551 break;
553 case SfxItemState::DEFAULT:
554 ClearItem( nWhich );
555 break;
557 case SfxItemState::DONTCARE:
558 InvalidateItem( nWhich );
559 break;
561 default:
562 assert(!"invalid Argument for eDefaultAs");
569 * Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
570 * items which are new ranges too.
572 void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
574 // special case: exactly one sal_uInt16 which is already included?
575 if (nFrom == nTo)
576 if (SfxItemState eItemState = GetItemState(nFrom, false);
577 eItemState == SfxItemState::DEFAULT || eItemState == SfxItemState::SET)
578 return;
580 auto pNewRanges = m_pWhichRanges.MergeRange(nFrom, nTo);
581 RecreateRanges_Impl(pNewRanges);
582 m_pWhichRanges = std::move(pNewRanges);
586 * Modifies the ranges of settable items. Keeps state of items which
587 * are new ranges too.
589 void SfxItemSet::SetRanges( const WhichRangesContainer& pNewRanges )
591 // Identical Ranges?
592 if (m_pWhichRanges == pNewRanges)
593 return;
594 assert(svl::detail::validRanges2(pNewRanges));
595 RecreateRanges_Impl(pNewRanges);
596 m_pWhichRanges = pNewRanges;
599 void SfxItemSet::SetRanges( WhichRangesContainer&& pNewRanges )
601 // Identical Ranges?
602 if (m_pWhichRanges == pNewRanges)
603 return;
604 assert(svl::detail::validRanges2(pNewRanges));
605 RecreateRanges_Impl(pNewRanges);
606 m_pWhichRanges = std::move(pNewRanges);
609 void SfxItemSet::RecreateRanges_Impl(const WhichRangesContainer& pNewRanges)
611 // create new item-array (by iterating through all new ranges)
612 const auto nSize = svl::detail::CountRanges(pNewRanges);
613 SfxPoolItem const** aNewItems = new const SfxPoolItem* [ nSize ];
614 sal_uInt16 nNewCount = 0;
615 if (m_nCount == 0)
616 memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
617 else
619 sal_uInt16 n = 0;
620 for ( auto const & pRange : pNewRanges )
622 // iterate through all ids in the range
623 for ( sal_uInt16 nWID = pRange.first; nWID <= pRange.second; ++nWID, ++n )
625 // direct move of pointer (not via pool)
626 SfxItemState eState = GetItemState( nWID, false, aNewItems+n );
627 if ( SfxItemState::SET == eState )
629 // increment new item count and possibly increment ref count
630 ++nNewCount;
631 aNewItems[n]->AddRef();
633 else if ( SfxItemState::DISABLED == eState )
635 // put "disabled" item
636 ++nNewCount;
637 aNewItems[n] = new SfxVoidItem(0);
639 else if ( SfxItemState::DONTCARE == eState )
641 ++nNewCount;
642 aNewItems[n] = INVALID_POOL_ITEM;
644 else
646 // default
647 aNewItems[n] = nullptr;
651 // free old items
652 sal_uInt16 nOldTotalCount = TotalCount();
653 for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
655 const SfxPoolItem *pItem = m_ppItems[nItem];
656 if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
657 m_pPool->Remove(*pItem);
661 // replace old items-array and ranges
662 if (m_bItemsFixed)
663 m_bItemsFixed = false;
664 else
665 delete[] m_ppItems;
666 m_ppItems = aNewItems;
667 m_nCount = nNewCount;
671 * The SfxItemSet takes over exactly those SfxPoolItems that are
672 * set in rSet and are in their own Which range. All others are removed.
673 * The SfxItemPool is retained, such that SfxPoolItems that have been
674 * taken over, are moved from the rSet's SfxItemPool to the SfxItemPool
675 * of *this.
677 * SfxPoolItems in rSet, for which holds 'IsInvalidItem() == true' are
678 * taken over as invalid items.
680 * @return bool true
681 * SfxPoolItems have been taken over
683 * false
684 * No SfxPoolItems have been taken over, because
685 * e.g. the Which ranges of SfxItemSets are not intersecting
686 * or the intersection does not contain SfxPoolItems that are
687 * set in rSet
689 bool SfxItemSet::Set
691 const SfxItemSet& rSet, /* The SfxItemSet, whose SfxPoolItems are
692 to been taken over */
694 bool bDeep /* true (default)
696 The SfxPoolItems from the parents that may
697 be present in rSet, are also taken over into
698 this SfxPoolItemSet
700 false
701 The SfxPoolItems from the parents of
702 rSet are not taken into account */
705 bool bRet = false;
706 if (m_nCount)
707 ClearItem();
708 if ( bDeep )
710 SfxWhichIter aIter(*this);
711 sal_uInt16 nWhich = aIter.FirstWhich();
712 while ( nWhich )
714 const SfxPoolItem* pItem;
715 if( SfxItemState::SET == rSet.GetItemState( nWhich, true, &pItem ) )
716 bRet |= nullptr != Put( *pItem, pItem->Which() );
717 nWhich = aIter.NextWhich();
720 else
721 bRet = Put(rSet, false);
723 return bRet;
726 const SfxPoolItem* SfxItemSet::GetItem(sal_uInt16 nId, bool bSearchInParent) const
728 // Convert to WhichId
729 sal_uInt16 nWhich = GetPool()->GetWhich(nId);
731 // Is the Item set or 'bDeep == true' available?
732 const SfxPoolItem *pItem = nullptr;
733 SfxItemState eState = GetItemState(nWhich, bSearchInParent, &pItem);
734 if (bSearchInParent && SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich))
736 pItem = &m_pPool->GetDefaultItem(nWhich);
739 return pItem;
742 const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, bool bSrchInParent) const
744 // Search the Range in which the Which is located in:
745 const SfxItemSet* pCurrentSet = this;
748 if( pCurrentSet->Count() )
750 SfxPoolItem const** ppFnd = pCurrentSet->m_ppItems;
751 for (auto const & pPtr : pCurrentSet->m_pWhichRanges)
753 if( pPtr.first <= nWhich && nWhich <= pPtr.second )
755 // In this Range
756 ppFnd += nWhich - pPtr.first;
757 if( *ppFnd )
759 if( IsInvalidItem(*ppFnd) ) {
760 //FIXME: The following code is duplicated further down
761 assert(m_pPool);
762 //!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
763 //!return aDefault;
764 return m_pPool->GetDefaultItem( nWhich );
766 #ifdef DBG_UTIL
767 const SfxPoolItem *pItem = *ppFnd;
768 if ( pItem->IsVoidItem() || !pItem->Which() )
769 SAL_INFO("svl.items", "SFX_WARNING: Getting disabled Item");
770 #endif
771 return **ppFnd;
773 break; // Continue with Parent
775 ppFnd += pPtr.second - pPtr.first + 1;
778 //TODO: Search until end of Range: What are we supposed to do now? To the Parent or Default??
779 // if( !*pPtr ) // Until the end of the search Range?
780 // break;
781 if (!bSrchInParent)
782 break;
783 pCurrentSet = pCurrentSet->m_pParent;
784 } while (nullptr != pCurrentSet);
786 // Get the Default from the Pool and return
787 assert(m_pPool);
788 return m_pPool->GetDefaultItem( nWhich );
792 * Notification callback
794 void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
798 sal_uInt16 SfxItemSet::TotalCount() const
800 return svl::detail::CountRanges(m_pWhichRanges);
804 * Only retain the Items that are also present in rSet
805 * (nevermind their value).
807 void SfxItemSet::Intersect( const SfxItemSet& rSet )
809 assert(m_pPool && "Not implemented without Pool");
810 if( !Count() ) // None set?
811 return;
813 // Delete all Items not contained in rSet
814 if( !rSet.Count() )
816 ClearItem(); // Delete everything
817 return;
820 // If the Ranges are identical, we can easily process it
821 if( m_pWhichRanges == rSet.m_pWhichRanges )
823 sal_uInt16 nSize = TotalCount();
824 SfxPoolItem const** ppFnd1 = m_ppItems;
825 SfxPoolItem const** ppFnd2 = rSet.m_ppItems;
827 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
828 if( *ppFnd1 && !*ppFnd2 )
830 // Delete from Pool
831 if( !IsInvalidItem( *ppFnd1 ) )
833 sal_uInt16 nWhich = (*ppFnd1)->Which();
834 if (SfxItemPool::IsWhich(nWhich))
836 const SfxPoolItem& rNew = m_pParent
837 ? m_pParent->Get( nWhich )
838 : m_pPool->GetDefaultItem( nWhich );
840 Changed( **ppFnd1, rNew );
842 m_pPool->Remove( **ppFnd1 );
844 *ppFnd1 = nullptr;
845 --m_nCount;
848 else
850 SfxItemIter aIter( *this );
851 const SfxPoolItem* pItem = aIter.GetCurItem();
854 sal_uInt16 nWhich = IsInvalidItem( pItem )
855 ? GetWhichByPos( aIter.GetCurPos() )
856 : pItem->Which();
857 if( SfxItemState::UNKNOWN == rSet.GetItemState( nWhich, false ) )
858 ClearItem( nWhich ); // Delete
859 pItem = aIter.NextItem();
860 } while (pItem);
864 void SfxItemSet::Differentiate( const SfxItemSet& rSet )
866 if( !Count() || !rSet.Count() )// None set?
867 return;
869 // If the Ranges are identical, we can easily process it
870 if( m_pWhichRanges == rSet.m_pWhichRanges )
872 sal_uInt16 nSize = TotalCount();
873 SfxPoolItem const** ppFnd1 = m_ppItems;
874 SfxPoolItem const** ppFnd2 = rSet.m_ppItems;
876 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
877 if( *ppFnd1 && *ppFnd2 )
879 // Delete from Pool
880 if( !IsInvalidItem( *ppFnd1 ) )
882 sal_uInt16 nWhich = (*ppFnd1)->Which();
883 if (SfxItemPool::IsWhich(nWhich))
885 const SfxPoolItem& rNew = m_pParent
886 ? m_pParent->Get( nWhich )
887 : m_pPool->GetDefaultItem( nWhich );
889 Changed( **ppFnd1, rNew );
891 m_pPool->Remove( **ppFnd1 );
893 *ppFnd1 = nullptr;
894 --m_nCount;
897 else
899 SfxItemIter aIter( *this );
900 const SfxPoolItem* pItem = aIter.GetCurItem();
903 sal_uInt16 nWhich = IsInvalidItem( pItem )
904 ? GetWhichByPos( aIter.GetCurPos() )
905 : pItem->Which();
906 if( SfxItemState::SET == rSet.GetItemState( nWhich, false ) )
907 ClearItem( nWhich ); // Delete
908 pItem = aIter.NextItem();
909 } while (pItem);
915 * Decision table for MergeValue(s)
917 * Principles:
918 * 1. If the Which value in the 1st set is "unknown", there's never any action
919 * 2. If the Which value in the 2nd set is "unknown", it's made the "default"
920 * 3. For comparisons the values of the "default" Items are take into account
922 * 1st Item 2nd Item Values bIgnoreDefs Remove Assign Add
924 * set set == sal_False - - -
925 * default set == sal_False - - -
926 * dontcare set == sal_False - - -
927 * unknown set == sal_False - - -
928 * set default == sal_False - - -
929 * default default == sal_False - - -
930 * dontcare default == sal_False - - -
931 * unknown default == sal_False - - -
932 * set dontcare == sal_False 1st Item -1 -
933 * default dontcare == sal_False - -1 -
934 * dontcare dontcare == sal_False - - -
935 * unknown dontcare == sal_False - - -
936 * set unknown == sal_False 1st Item -1 -
937 * default unknown == sal_False - - -
938 * dontcare unknown == sal_False - - -
939 * unknown unknown == sal_False - - -
941 * set set != sal_False 1st Item -1 -
942 * default set != sal_False - -1 -
943 * dontcare set != sal_False - - -
944 * unknown set != sal_False - - -
945 * set default != sal_False 1st Item -1 -
946 * default default != sal_False - - -
947 * dontcare default != sal_False - - -
948 * unknown default != sal_False - - -
949 * set dontcare != sal_False 1st Item -1 -
950 * default dontcare != sal_False - -1 -
951 * dontcare dontcare != sal_False - - -
952 * unknown dontcare != sal_False - - -
953 * set unknown != sal_False 1st Item -1 -
954 * default unknown != sal_False - - -
955 * dontcare unknown != sal_False - - -
956 * unknown unknown != sal_False - - -
958 * set set == sal_True - - -
959 * default set == sal_True - 2nd Item 2nd Item
960 * dontcare set == sal_True - - -
961 * unknown set == sal_True - - -
962 * set default == sal_True - - -
963 * default default == sal_True - - -
964 * dontcare default == sal_True - - -
965 * unknown default == sal_True - - -
966 * set dontcare == sal_True - - -
967 * default dontcare == sal_True - -1 -
968 * dontcare dontcare == sal_True - - -
969 * unknown dontcare == sal_True - - -
970 * set unknown == sal_True - - -
971 * default unknown == sal_True - - -
972 * dontcare unknown == sal_True - - -
973 * unknown unknown == sal_True - - -
975 * set set != sal_True 1st Item -1 -
976 * default set != sal_True - 2nd Item 2nd Item
977 * dontcare set != sal_True - - -
978 * unknown set != sal_True - - -
979 * set default != sal_True - - -
980 * default default != sal_True - - -
981 * dontcare default != sal_True - - -
982 * unknown default != sal_True - - -
983 * set dontcare != sal_True 1st Item -1 -
984 * default dontcare != sal_True - -1 -
985 * dontcare dontcare != sal_True - - -
986 * unknown dontcare != sal_True - - -
987 * set unknown != sal_True - - -
988 * default unknown != sal_True - - -
989 * dontcare unknown != sal_True - - -
990 * unknown unknown != sal_True - - -
992 static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
993 const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
994 bool bIgnoreDefaults )
996 assert(ppFnd1 != nullptr && "Merging to 0-Item");
998 // 1st Item is Default?
999 if ( !*ppFnd1 )
1001 if ( IsInvalidItem(pFnd2) )
1002 // Decision table: default, dontcare, doesn't matter, doesn't matter
1003 *ppFnd1 = INVALID_POOL_ITEM;
1005 else if ( pFnd2 && !bIgnoreDefaults &&
1006 _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
1007 // Decision table: default, set, !=, sal_False
1008 *ppFnd1 = INVALID_POOL_ITEM;
1010 else if ( pFnd2 && bIgnoreDefaults )
1011 // Decision table: default, set, doesn't matter, sal_True
1012 *ppFnd1 = &_pPool->Put( *pFnd2 );
1014 if ( *ppFnd1 )
1015 ++rCount;
1018 // 1st Item set?
1019 else if ( !IsInvalidItem(*ppFnd1) )
1021 if ( !pFnd2 )
1023 // 2nd Item is Default
1024 if ( !bIgnoreDefaults &&
1025 **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
1027 // Decision table: set, default, !=, sal_False
1028 _pPool->Remove( **ppFnd1 );
1029 *ppFnd1 = INVALID_POOL_ITEM;
1032 else if ( IsInvalidItem(pFnd2) )
1034 // 2nd Item is dontcare
1035 if ( !bIgnoreDefaults ||
1036 **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
1038 // Decision table: set, dontcare, doesn't matter, sal_False
1039 // or: set, dontcare, !=, sal_True
1040 _pPool->Remove( **ppFnd1 );
1041 *ppFnd1 = INVALID_POOL_ITEM;
1044 else
1046 // 2nd Item is set
1047 if ( **ppFnd1 != *pFnd2 )
1049 // Decision table: set, set, !=, doesn't matter
1050 _pPool->Remove( **ppFnd1 );
1051 *ppFnd1 = INVALID_POOL_ITEM;
1057 void SfxItemSet::MergeValues( const SfxItemSet& rSet )
1059 // WARNING! When making changes/fixing bugs, always update the table above!!
1060 assert( GetPool() == rSet.GetPool() && "MergeValues with different Pools" );
1062 // If the Ranges match, they are easier to process!
1063 if( m_pWhichRanges == rSet.m_pWhichRanges )
1065 sal_uInt16 nSize = TotalCount();
1066 SfxPoolItem const** ppFnd1 = m_ppItems;
1067 SfxPoolItem const** ppFnd2 = rSet.m_ppItems;
1069 for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
1070 MergeItem_Impl(m_pPool, m_nCount, ppFnd1, *ppFnd2, false/*bIgnoreDefaults*/);
1072 else
1074 SfxWhichIter aIter( rSet );
1075 sal_uInt16 nWhich;
1076 while( 0 != ( nWhich = aIter.NextWhich() ) )
1078 const SfxPoolItem* pItem = nullptr;
1079 (void)rSet.GetItemState( nWhich, true, &pItem );
1080 if( !pItem )
1082 // Not set, so default
1083 MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ) );
1085 else if( IsInvalidItem( pItem ) )
1086 // don't care
1087 InvalidateItem( nWhich );
1088 else
1089 MergeValue( *pItem );
1094 void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, bool bIgnoreDefaults )
1096 SfxPoolItem const** ppFnd = m_ppItems;
1097 const sal_uInt16 nWhich = rAttr.Which();
1098 for( auto const & pPtr : m_pWhichRanges )
1100 // In this Range??
1101 if( pPtr.first <= nWhich && nWhich <= pPtr.second )
1103 ppFnd += nWhich - pPtr.first;
1104 MergeItem_Impl(m_pPool, m_nCount, ppFnd, &rAttr, bIgnoreDefaults);
1105 break;
1107 ppFnd += pPtr.second - pPtr.first + 1;
1111 void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
1113 SfxPoolItem const** ppFnd = m_ppItems;
1114 for( auto const & pPtr : m_pWhichRanges )
1116 if( pPtr.first <= nWhich && nWhich <= pPtr.second )
1118 // In this Range?
1119 ppFnd += nWhich - pPtr.first;
1121 if( *ppFnd ) // Set for me
1123 if( !IsInvalidItem(*ppFnd) )
1125 m_pPool->Remove( **ppFnd );
1126 *ppFnd = INVALID_POOL_ITEM;
1129 else
1131 *ppFnd = INVALID_POOL_ITEM;
1132 ++m_nCount;
1134 break;
1136 ppFnd += pPtr.second - pPtr.first + 1;
1140 sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
1142 sal_uInt16 n = 0;
1143 for( auto const & pPtr : m_pWhichRanges )
1145 n = ( pPtr.second - pPtr.first ) + 1;
1146 if( nPos < n )
1147 return pPtr.first + nPos;
1148 nPos = nPos - n;
1150 assert(false);
1151 return 0;
1154 bool SfxItemSet::operator==(const SfxItemSet &rCmp) const
1156 return Equals( rCmp, true);
1159 bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool bComparePool) const
1161 // Values we can get quickly need to be the same
1162 const bool bDifferentPools = (m_pPool != rCmp.m_pPool);
1163 if ( (bComparePool && m_pParent != rCmp.m_pParent) ||
1164 (bComparePool && bDifferentPools) ||
1165 Count() != rCmp.Count() )
1166 return false;
1168 // If we reach here and bDifferentPools==true that means bComparePool==false.
1170 // Counting Ranges takes longer; they also need to be the same, however
1171 sal_uInt16 nCount1 = TotalCount();
1172 sal_uInt16 nCount2 = rCmp.TotalCount();
1173 if ( nCount1 != nCount2 )
1174 return false;
1176 // Are the Ranges themselves unequal?
1177 for (sal_Int32 i = 0; i < m_pWhichRanges.size(); ++i)
1179 if (m_pWhichRanges[i] != rCmp.m_pWhichRanges[i])
1181 // We must use the slow method then
1182 SfxWhichIter aIter( *this );
1183 for ( sal_uInt16 nWh = aIter.FirstWhich();
1184 nWh;
1185 nWh = aIter.NextWhich() )
1187 // If the pointer of the poolable Items are unequal, the Items must match
1188 const SfxPoolItem *pItem1 = nullptr, *pItem2 = nullptr;
1189 if ( GetItemState( nWh, false, &pItem1 ) !=
1190 rCmp.GetItemState( nWh, false, &pItem2 ) ||
1191 ( pItem1 != pItem2 &&
1192 ( !pItem1 || IsInvalidItem(pItem1) ||
1193 (m_pPool->IsItemPoolable(*pItem1) &&
1194 *pItem1 != *pItem2 ) ) ) )
1195 return false;
1198 return true;
1202 // Are all pointers the same?
1203 if (0 == memcmp( m_ppItems, rCmp.m_ppItems, nCount1 * sizeof(m_ppItems[0]) ))
1204 return true;
1206 // We need to compare each one separately then
1207 const SfxPoolItem **ppItem1 = m_ppItems;
1208 const SfxPoolItem **ppItem2 = rCmp.m_ppItems;
1209 for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
1211 // If the pointers of the poolable Items are not the same, the Items
1212 // must match
1213 if ( *ppItem1 != *ppItem2 &&
1214 ( ( !*ppItem1 || !*ppItem2 ) ||
1215 ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
1216 (!bDifferentPools && m_pPool->IsItemPoolable(**ppItem1)) ||
1217 **ppItem1 != **ppItem2 ) )
1218 return false;
1220 ++ppItem1;
1221 ++ppItem2;
1224 return true;
1227 std::unique_ptr<SfxItemSet> SfxItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1229 if (pToPool && pToPool != m_pPool)
1231 std::unique_ptr<SfxItemSet> pNewSet(new SfxItemSet(*pToPool, m_pWhichRanges));
1232 if ( bItems )
1234 SfxWhichIter aIter(*pNewSet);
1235 sal_uInt16 nWhich = aIter.FirstWhich();
1236 while ( nWhich )
1238 const SfxPoolItem* pItem;
1239 if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) )
1240 pNewSet->Put( *pItem, pItem->Which() );
1241 nWhich = aIter.NextWhich();
1244 return pNewSet;
1246 else
1247 return std::unique_ptr<SfxItemSet>(bItems
1248 ? new SfxItemSet(*this)
1249 : new SfxItemSet(*m_pPool, m_pWhichRanges));
1252 SfxItemSet SfxItemSet::CloneAsValue(bool bItems, SfxItemPool *pToPool ) const
1254 if (pToPool && pToPool != m_pPool)
1256 SfxItemSet aNewSet(*pToPool, m_pWhichRanges);
1257 if ( bItems )
1259 SfxWhichIter aIter(aNewSet);
1260 sal_uInt16 nWhich = aIter.FirstWhich();
1261 while ( nWhich )
1263 const SfxPoolItem* pItem;
1264 if ( SfxItemState::SET == GetItemState( nWhich, false, &pItem ) )
1265 aNewSet.Put( *pItem, pItem->Which() );
1266 nWhich = aIter.NextWhich();
1269 return aNewSet;
1271 else
1272 return bItems
1273 ? *this
1274 : SfxItemSet(*m_pPool, m_pWhichRanges);
1277 void SfxItemSet::PutDirect(const SfxPoolItem &rItem)
1279 SfxPoolItem const** ppFnd = m_ppItems;
1280 const sal_uInt16 nWhich = rItem.Which();
1281 #ifdef DBG_UTIL
1282 IsPoolDefaultItem(&rItem) || m_pPool->CheckItemInPool(&rItem);
1283 // Only cause assertion in the callees
1284 #endif
1285 for( auto const & pPtr : m_pWhichRanges)
1287 if( pPtr.first <= nWhich && nWhich <= pPtr.second )
1289 // In this Range?
1290 ppFnd += nWhich - pPtr.first;
1291 const SfxPoolItem* pOld = *ppFnd;
1292 if( pOld ) // One already present
1294 if( rItem == **ppFnd )
1295 return; // Already present!
1296 m_pPool->Remove( *pOld );
1298 else
1299 ++m_nCount;
1301 // Add the new one
1302 if( IsPoolDefaultItem(&rItem) )
1303 *ppFnd = &m_pPool->Put( rItem );
1304 else
1306 *ppFnd = &rItem;
1307 if( !IsStaticDefaultItem( &rItem ) )
1308 rItem.AddRef();
1311 return;
1313 ppFnd += pPtr.second - pPtr.first + 1;
1317 void SfxItemSet::dumpAsXml(xmlTextWriterPtr pWriter) const
1319 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemSet"));
1320 SfxItemIter aIter(*this);
1321 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
1323 if (IsInvalidItem(pItem))
1325 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("invalid"));
1326 (void)xmlTextWriterEndElement(pWriter);
1328 else
1330 pItem->dumpAsXml(pWriter);
1333 (void)xmlTextWriterEndElement(pWriter);
1337 // ----------------------------------------------- class SfxAllItemSet
1339 SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
1340 : SfxItemSet(rPool, SfxAllItemSetFlag::Flag)
1344 SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
1345 : SfxItemSet(rCopy)
1350 * Explicitly define this ctor to avoid auto-generation by the compiler.
1351 * The compiler does not take the ctor with the 'const SfxItemSet&'!
1353 SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
1354 : SfxItemSet(rCopy)
1359 * Putting with automatic extension of the WhichId with the ID of the Item.
1361 const SfxPoolItem* SfxAllItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
1363 MergeRange(nWhich, nWhich);
1364 return SfxItemSet::PutImpl(rItem, nWhich, bPassingOwnership);
1368 * Disable Item
1369 * Using a VoidItem with Which value 0
1371 void SfxItemSet::DisableItem(sal_uInt16 nWhich)
1373 Put( SfxVoidItem(0), nWhich );
1376 std::unique_ptr<SfxItemSet> SfxAllItemSet::Clone(bool bItems, SfxItemPool *pToPool ) const
1378 if (pToPool && pToPool != m_pPool)
1380 std::unique_ptr<SfxAllItemSet> pNewSet(new SfxAllItemSet( *pToPool ));
1381 if ( bItems )
1382 pNewSet->Set( *this );
1383 return pNewSet;
1385 else
1386 return std::unique_ptr<SfxItemSet>(bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*m_pPool));
1389 SfxItemSet SfxAllItemSet::CloneAsValue(bool , SfxItemPool * ) const
1391 // if you are trying to clone, then the thing you are cloning is polymorphic, which means
1392 // it cannot be cloned as a value
1393 throw std::logic_error("cannot do this");
1399 WhichRangesContainer::WhichRangesContainer( const WhichPair* wids, sal_Int32 nSize )
1401 auto p = new WhichPair[nSize];
1402 for (int i=0; i<nSize; ++i)
1403 p[i] = wids[i];
1404 m_pairs = p;
1405 m_size = nSize;
1406 m_bOwnRanges = true;
1409 WhichRangesContainer::WhichRangesContainer(sal_uInt16 nWhichStart, sal_uInt16 nWhichEnd)
1410 : m_size(1), m_bOwnRanges(true)
1412 auto p = new WhichPair[1];
1413 p[0] = { nWhichStart, nWhichEnd };
1414 m_pairs = p;
1417 WhichRangesContainer::WhichRangesContainer(WhichRangesContainer && other)
1419 std::swap(m_pairs, other.m_pairs);
1420 std::swap(m_size, other.m_size);
1421 std::swap(m_bOwnRanges, other.m_bOwnRanges);
1424 WhichRangesContainer& WhichRangesContainer::operator=(WhichRangesContainer && other)
1426 std::swap(m_pairs, other.m_pairs);
1427 std::swap(m_size, other.m_size);
1428 std::swap(m_bOwnRanges, other.m_bOwnRanges);
1429 return *this;
1432 WhichRangesContainer& WhichRangesContainer::operator=(WhichRangesContainer const & other)
1434 reset();
1435 m_size = other.m_size;
1436 m_bOwnRanges = other.m_bOwnRanges;
1437 if (m_bOwnRanges)
1439 auto p = new WhichPair[m_size];
1440 for (int i=0; i<m_size; ++i)
1441 p[i] = other.m_pairs[i];
1442 m_pairs = p;
1444 else
1445 m_pairs = other.m_pairs;
1446 return *this;
1449 WhichRangesContainer::~WhichRangesContainer()
1451 reset();
1454 bool WhichRangesContainer::operator==(WhichRangesContainer const & other) const
1456 if (m_size != other.m_size)
1457 return false;
1458 if (m_pairs == other.m_pairs)
1459 return true;
1460 return std::equal(m_pairs, m_pairs + m_size, other.m_pairs, other.m_pairs + m_size);
1464 void WhichRangesContainer::reset()
1466 if (m_bOwnRanges)
1468 delete [] m_pairs;
1469 m_bOwnRanges = false;
1471 m_pairs = nullptr;
1472 m_size = 0;
1475 // Adds a range to which ranges, keeping the ranges in valid state (sorted, non-overlapping)
1476 WhichRangesContainer WhichRangesContainer::MergeRange(sal_uInt16 nFrom,
1477 sal_uInt16 nTo) const
1479 assert(svl::detail::validRange(nFrom, nTo));
1481 if (empty())
1482 return WhichRangesContainer(nFrom, nTo);
1484 // create vector of ranges (sal_uInt16 pairs of lower and upper bound)
1485 const size_t nOldCount = size();
1486 std::vector<WhichPair> aRangesTable;
1487 aRangesTable.reserve(nOldCount);
1488 bool bAdded = false;
1489 for (const auto& rPair : *this)
1491 if (!bAdded && rPair.first >= nFrom)
1492 { // insert new range, keep ranges sorted
1493 aRangesTable.push_back({ nFrom, nTo });
1494 bAdded = true;
1496 // insert current range
1497 aRangesTable.emplace_back(rPair);
1499 if (!bAdded)
1500 aRangesTable.push_back({ nFrom, nTo });
1502 // true if ranges overlap or adjoin, false if ranges are separate
1503 auto needMerge = [](WhichPair lhs, WhichPair rhs) {
1504 return (lhs.first - 1) <= rhs.second && (rhs.first - 1) <= lhs.second;
1507 auto it = aRangesTable.begin();
1508 // we got at least one range
1509 for (;;)
1511 auto itNext = std::next(it);
1512 if (itNext == aRangesTable.end())
1513 break;
1514 // check neighbouring ranges, find first range which overlaps or adjoins a previous range
1515 if (needMerge(*it, *itNext))
1517 // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first)
1518 it->second = std::max(it->second, itNext->second);
1519 aRangesTable.erase(itNext);
1521 else
1522 ++it;
1525 return WhichRangesContainer(aRangesTable.data(), aRangesTable.size());
1528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */