Avoid potential negative array index access to cached text.
[LibreOffice.git] / include / svl / itemset.hxx
blob774fe131c16ccffec548746aa5761931ef69f2ae
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 .
19 #pragma once
21 #include <sal/config.h>
23 #include <cassert>
24 #include <memory>
25 #include <utility>
27 #include <svl/svldllapi.h>
28 #include <svl/poolitem.hxx>
29 #include <svl/typedwhich.hxx>
30 #include <svl/whichranges.hxx>
32 class SfxItemPool;
34 #ifdef DBG_UTIL
35 SVL_DLLPUBLIC size_t getAllocatedSfxItemSetCount();
36 SVL_DLLPUBLIC size_t getUsedSfxItemSetCount();
37 SVL_DLLPUBLIC size_t getAllocatedSfxPoolItemHolderCount();
38 SVL_DLLPUBLIC size_t getUsedSfxPoolItemHolderCount();
39 #endif
41 // ItemSet/ItemPool helpers
42 SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, sal_uInt16 nWhich, bool bPassingOwnership);
43 void implCleanupItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource);
45 class SAL_WARN_UNUSED SVL_DLLPUBLIC SfxPoolItemHolder
47 SfxItemPool* m_pPool;
48 const SfxPoolItem* m_pItem;
49 #ifndef NDEBUG
50 bool m_bDeleted;
51 #endif
52 public:
53 SfxPoolItemHolder();
54 SfxPoolItemHolder(SfxItemPool&, const SfxPoolItem*, bool bPassingOwnership = false);
55 SfxPoolItemHolder(const SfxPoolItemHolder&);
56 ~SfxPoolItemHolder();
58 #ifndef NDEBUG
59 bool isDeleted() const { return m_bDeleted; }
60 #endif
62 const SfxPoolItemHolder& operator=(const SfxPoolItemHolder&);
63 bool operator==(const SfxPoolItemHolder &) const;
64 SfxItemPool& getPool() const { assert(!isDeleted() && "Destructed instance used (!)"); return *m_pPool; }
65 const SfxPoolItem* getItem() const { assert(!isDeleted() && "Destructed instance used (!)"); return m_pItem; }
66 sal_uInt16 Which() const { if(nullptr != m_pItem) return m_pItem->Which(); return 0; }
69 class SAL_WARN_UNUSED SVL_DLLPUBLIC SfxItemSet
71 friend class SfxItemIter;
72 friend class SfxWhichIter;
74 // allow ItemSetTooling to access
75 friend SfxPoolItem const* implCreateItemEntry(SfxItemPool&, SfxPoolItem const*, sal_uInt16, bool);
76 friend void implCleanupItemEntry(SfxItemPool&, SfxPoolItem const*);
78 SfxItemPool* m_pPool; ///< pool that stores the items
79 const SfxItemSet* m_pParent; ///< derivation
80 sal_uInt16 m_nCount; ///< number of items
81 sal_uInt16 m_nTotalCount; ///< number of WhichIDs, also size of m_ppItems array
83 // bitfield (better packaging if a bool needs to be added)
84 bool m_bItemsFixed : 1; ///< true if this is a SfxItemSetFixed object, so does not *own* m_ppItems
86 SfxPoolItem const** m_ppItems; ///< pointer to array of items, we allocate and free this unless m_bItemsFixed==true
87 WhichRangesContainer m_pWhichRanges; ///< array of Which Ranges
89 // Notification-Callback mechanism for SwAttrSet in SW, functionPtr for callback
90 std::function<void(const SfxPoolItem*, const SfxPoolItem*)> m_aCallback;
92 protected:
93 // Notification-Callback mechanism for SwAttrSet in SW
94 void setCallback(const std::function<void(const SfxPoolItem*, const SfxPoolItem*)> &func) { m_aCallback = func; }
95 void clearCallback() { m_aCallback = nullptr; }
97 // container library interface support
98 // only for internal use (for now), thus protected
99 using const_iterator = SfxPoolItem const**;
101 const_iterator begin() const noexcept { return m_ppItems; }
102 const_iterator end() const noexcept { return begin() + m_nTotalCount; }
104 bool empty() const noexcept { return 0 == m_nTotalCount; }
105 sal_Int32 size() const noexcept { return m_nTotalCount; }
106 SfxPoolItem const* operator[](sal_Int32 idx) const noexcept
108 assert(idx >= 0 && idx < m_nTotalCount && "index out of range");
109 return m_ppItems[idx];
112 friend class SfxAllItemSet;
114 private:
115 SVL_DLLPRIVATE void RecreateRanges_Impl(const WhichRangesContainer& pNewRanges);
117 public:
118 SfxPoolItem const** GetItems_Impl() const { return m_ppItems; }
120 private:
121 const SfxItemSet& operator=(const SfxItemSet &) = delete;
123 protected:
124 virtual const SfxPoolItem* PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bPassingOwnership );
126 /** special constructor for SfxAllItemSet */
127 enum class SfxAllItemSetFlag { Flag };
128 SfxItemSet( SfxItemPool&, SfxAllItemSetFlag );
129 /** special constructor for SfxItemSetFixed */
130 SfxItemSet( SfxItemPool&, WhichRangesContainer&& ranges, SfxPoolItem const ** ppItems, sal_uInt16 nTotalCount );
132 public:
133 SfxItemSet( const SfxItemSet& );
134 SfxItemSet( SfxItemSet&& ) noexcept;
135 SfxItemSet( SfxItemPool& );
136 SfxItemSet( SfxItemPool&, WhichRangesContainer ranges );
138 SfxItemSet( SfxItemPool& rPool, sal_uInt16 nWhichStart, sal_uInt16 nWhichEnd )
139 : SfxItemSet(rPool, WhichRangesContainer(nWhichStart, nWhichEnd)) {}
141 template<sal_uInt16... WIDs>
142 SfxItemSet(SfxItemPool& pool, svl::Items_t<WIDs...> wids)
143 : SfxItemSet(pool, WhichRangesContainer(wids)) {}
145 virtual ~SfxItemSet();
147 virtual std::unique_ptr<SfxItemSet> Clone(bool bItems = true, SfxItemPool *pToPool = nullptr) const;
148 /** note that this only works if you know for sure that you are dealing with an SfxItemSet
149 and not one of it's subclasses. */
150 SfxItemSet CloneAsValue(bool bItems = true, SfxItemPool *pToPool = nullptr) const;
152 // Get number of items
153 sal_uInt16 Count() const { return m_nCount; }
154 sal_uInt16 TotalCount() const { return m_nTotalCount; }
156 const SfxPoolItem& Get( sal_uInt16 nWhich, bool bSrchInParent = true ) const;
157 template<class T>
158 const T& Get( TypedWhichId<T> nWhich, bool bSrchInParent = true ) const
160 return static_cast<const T&>(Get(sal_uInt16(nWhich), bSrchInParent));
163 /** This method eases accessing single Items in the SfxItemSet.
165 @param nId SlotId or the Item's WhichId
166 @param bSearchInParent also search in parent ItemSets
167 @returns 0 if the ItemSet does not contain an Item with the Id 'nWhich'
169 const SfxPoolItem* GetItem(sal_uInt16 nWhich, bool bSearchInParent = true) const;
171 /// Templatized version of GetItem() to directly return the correct type.
172 template<class T> const T* GetItem(sal_uInt16 nWhich, bool bSearchInParent = true) const
174 const SfxPoolItem* pItem = GetItem(nWhich, bSearchInParent);
175 const T* pCastedItem = dynamic_cast<const T*>(pItem);
177 assert(!pItem || pCastedItem); // if it exists, must have the correct type
178 return pCastedItem;
180 template<class T> const T* GetItem( TypedWhichId<T> nWhich, bool bSearchInParent = true ) const
182 return GetItem<T>(sal_uInt16(nWhich), bSearchInParent);
186 /// Templatized static version of GetItem() to directly return the correct type if the SfxItemSet is available.
187 template<class T> static const T* GetItem(const SfxItemSet* pItemSet, sal_uInt16 nWhich, bool bSearchInParent)
189 if (pItemSet)
190 return pItemSet->GetItem<T>(nWhich, bSearchInParent);
192 return nullptr;
194 template <class T>
195 static const T* GetItem(const SfxItemSet* pItemSet, TypedWhichId<T> nWhich,
196 bool bSearchInParent)
198 return GetItem<T>(pItemSet, static_cast<sal_uInt16>(nWhich), bSearchInParent);
201 sal_uInt16 GetWhichByOffset(sal_uInt16 nOffset) const;
203 SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent = true, const SfxPoolItem **ppItem = nullptr) const
205 // use local helper, start value for looped-through SfxItemState value is SfxItemState::UNKNOWN
206 return GetItemState_ForWhichID(SfxItemState::UNKNOWN, nWhich, bSrchInParent, ppItem);
209 template <class T> SfxItemState GetItemState(TypedWhichId<T> nWhich, bool bSrchInParent = true, const T **ppItem = nullptr ) const
211 // use local helper, start value for looped-through SfxItemState value is SfxItemState::UNKNOWN
212 return GetItemState_ForWhichID(SfxItemState::UNKNOWN, sal_uInt16(nWhich), bSrchInParent, reinterpret_cast<SfxPoolItem const**>(ppItem));
215 /// Templatized version of GetItemState() to directly return the correct type.
216 template<class T>
217 const T * GetItemIfSet( TypedWhichId<T> nWhich,
218 bool bSrchInParent = true ) const
220 const SfxPoolItem * pItem = nullptr;
221 if (SfxItemState::SET == GetItemState_ForWhichID(SfxItemState::UNKNOWN, sal_uInt16(nWhich), bSrchInParent, &pItem))
222 return static_cast<const T*>(pItem);
223 return nullptr;
226 bool HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem = nullptr) const;
227 template<class T>
228 bool HasItem(TypedWhichId<T> nWhich, const T** ppItem = nullptr) const
229 { return HasItem(sal_uInt16(nWhich), reinterpret_cast<const SfxPoolItem**>(ppItem)); }
231 void DisableItem(sal_uInt16 nWhich);
232 void InvalidateItem(sal_uInt16 nWhich)
233 { InvalidateItem_ForWhichID(nWhich); }
234 sal_uInt16 ClearItem( sal_uInt16 nWhich = 0);
235 void ClearInvalidItems();
236 void InvalidateAllItems(); // HACK(via nWhich = 0) ???
238 inline void SetParent( const SfxItemSet* pNew );
240 // add, delete items, work on items
241 public:
242 const SfxPoolItem* Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
243 { return PutImpl(rItem, nWhich, /*bPassingOwnership*/false); }
244 const SfxPoolItem* Put( std::unique_ptr<SfxPoolItem> xItem, sal_uInt16 nWhich )
245 { return PutImpl(*xItem.release(), nWhich, /*bPassingOwnership*/true); }
246 const SfxPoolItem* Put( const SfxPoolItem& rItem )
247 { return Put(rItem, rItem.Which()); }
248 const SfxPoolItem* Put( std::unique_ptr<SfxPoolItem> xItem )
249 { auto nWhich = xItem->Which(); return Put(std::move(xItem), nWhich); }
250 bool Put( const SfxItemSet&,
251 bool bInvalidAsDefault = true );
252 void PutExtended( const SfxItemSet&,
253 SfxItemState eDontCareAs,
254 SfxItemState eDefaultAs );
256 bool Set( const SfxItemSet&, bool bDeep = true );
258 void Intersect( const SfxItemSet& rSet );
259 void MergeValues( const SfxItemSet& rSet );
260 void Differentiate( const SfxItemSet& rSet );
261 void MergeValue( const SfxPoolItem& rItem, bool bOverwriteDefaults = false );
263 SfxItemPool* GetPool() const { return m_pPool; }
264 const WhichRangesContainer & GetRanges() const { return m_pWhichRanges; }
265 void SetRanges( const WhichRangesContainer& );
266 void SetRanges( WhichRangesContainer&& );
267 void MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo );
268 const SfxItemSet* GetParent() const { return m_pParent; }
270 bool operator==(const SfxItemSet &) const;
272 /** Compare possibly ignoring SfxItemPool pointer.
274 This can be used to compare the content of two SfxItemSet even if they
275 don't share the same pool. EditTextObject::Equals(...,false) uses this
276 which is needed in ScGlobal::EETextObjEqual() for
277 ScPageHFItem::operator==()
279 @param bComparePool
280 if <FALSE/> ignore SfxItemPool pointer,
281 if <TRUE/> compare also SfxItemPool pointer (identical to operator==())
283 bool Equals(const SfxItemSet &, bool bComparePool) const;
285 void dumpAsXml(xmlTextWriterPtr pWriter) const;
287 private:
288 // split version(s) of ClearSingleItemImpl for input types WhichID and Offset
289 sal_uInt16 ClearSingleItem_ForWhichID( sal_uInt16 nWhich );
290 sal_uInt16 ClearSingleItem_ForOffset( sal_uInt16 nOffset );
292 // cleanup all Items, but do not reset/change m_ppItems array. That is
293 // responsibility of the caller & allows specific resets
294 sal_uInt16 ClearAllItemsImpl();
296 // Merge two given Item(entries)
297 void MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2, bool bIgnoreDefaults);
299 // split version(s) of InvalidateItem for input types WhichID and Offset
300 void InvalidateItem_ForWhichID(sal_uInt16 nWhich);
301 void InvalidateItem_ForOffset(sal_uInt16 nOffset);
303 // split version(s) of GetItemStateImpl for input types WhichID and Offset
304 SfxItemState GetItemState_ForWhichID( SfxItemState eState, sal_uInt16 nWhich, bool bSrchInParent, const SfxPoolItem **ppItem) const;
305 SfxItemState GetItemState_ForOffset( sal_uInt16 nOffset, const SfxPoolItem **ppItem) const;
308 inline void SfxItemSet::SetParent( const SfxItemSet* pNew )
310 m_pParent = pNew;
313 class SVL_DLLPUBLIC SfxAllItemSet final : public SfxItemSet
315 // Handles all Ranges. Ranges are automatically modified by putting items.
318 public:
319 SfxAllItemSet( SfxItemPool &rPool );
320 SfxAllItemSet( const SfxItemSet & );
321 SfxAllItemSet( const SfxAllItemSet & );
323 virtual std::unique_ptr<SfxItemSet> Clone( bool bItems = true, SfxItemPool *pToPool = nullptr ) const override;
324 private:
325 virtual const SfxPoolItem* PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bPassingOwnership ) override;
329 namespace svl::detail
332 * Determines the number of sal_uInt16s in a container of pairs of
333 * sal_uInt16s, each representing a range of sal_uInt16s, and total capacity of the ranges.
335 template <sal_uInt16 WID1, sal_uInt16 WID2, sal_uInt16... Rest>
336 static constexpr sal_uInt16 CountRanges1()
338 sal_uInt16 nCapacity = rangeSize(WID1, WID2);
339 if constexpr (sizeof...(Rest) > 0)
340 nCapacity += CountRanges1<Rest...>();
341 return nCapacity;
344 // Allocate the items array inside the object, to reduce allocation cost.
346 template<sal_uInt16... WIDs>
347 class SfxItemSetFixed : public SfxItemSet
349 public:
350 SfxItemSetFixed( SfxItemPool& rPool)
351 : SfxItemSet(rPool, WhichRangesContainer(svl::Items_t<WIDs...>{}), m_aItems, NITEMS) {}
352 private:
353 static constexpr sal_uInt16 NITEMS = svl::detail::CountRanges1<WIDs...>();
354 const SfxPoolItem* m_aItems[NITEMS] = {};
357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */