[Libreoffice-commits] core.git: Branch 'distro/collabora/co-2021' - chart2/source include/svl sc/source sd/source sfx2/source starmath/source svl/source svx/source sw/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Mon Jun 14 17:32:43 UTC 2021


 chart2/source/controller/dialogs/dlg_NumberFormat.cxx     |   10 
 chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx |  111 ++--
 include/svl/itemset.hxx                                   |   39 +
 sc/source/ui/dbgui/validate.cxx                           |    2 
 sd/source/ui/func/fupage.cxx                              |   20 
 sfx2/source/control/bindings.cxx                          |   11 
 sfx2/source/dialog/tabdlg.cxx                             |   34 -
 starmath/source/unomodel.cxx                              |   12 
 svl/source/inc/items_helper.hxx                           |  126 ++++
 svl/source/items/itempool.cxx                             |   20 
 svl/source/items/itemset.cxx                              |  371 +-------------
 svx/source/dialog/hdft.cxx                                |   57 +-
 svx/source/svdraw/svdedxv.cxx                             |   34 -
 sw/source/core/bastyp/init.cxx                            |   18 
 sw/source/core/doc/docnew.cxx                             |    2 
 sw/source/core/docnode/ndtbl.cxx                          |   12 
 sw/source/core/fields/expfld.cxx                          |    8 
 sw/source/core/txtnode/txtedt.cxx                         |   11 
 sw/source/core/unocore/unocrsrhelper.cxx                  |   14 
 sw/source/uibase/app/docshini.cxx                         |    2 
 sw/source/uibase/lingu/hhcwrp.cxx                         |    7 
 sw/source/uibase/shells/tabsh.cxx                         |   28 -
 sw/source/uibase/shells/textsh.cxx                        |   15 
 sw/source/uibase/uiview/viewsrch.cxx                      |    2 
 sw/source/uibase/uno/SwXDocumentSettings.cxx              |   10 
 25 files changed, 397 insertions(+), 579 deletions(-)

New commits:
commit d8bb5bb58ef62bc0e32d17f00f5fe695c81b5606
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Jun 11 12:07:44 2021 +0200
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Mon Jun 14 19:32:07 2021 +0200

    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 at collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117106
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>

diff --git a/chart2/source/controller/dialogs/dlg_NumberFormat.cxx b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx
index d91b545cd027..3ba1bf68163f 100644
--- a/chart2/source/controller/dialogs/dlg_NumberFormat.cxx
+++ b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx
@@ -44,15 +44,11 @@ NumberFormatDialog::NumberFormatDialog(weld::Window* pParent, SfxItemSet& rSet)
 
 SfxItemSet NumberFormatDialog::CreateEmptyItemSetForNumberFormatDialog( SfxItemPool& rItemPool )
 {
-    static const sal_uInt16 nWhichPairs[] =
-    {
+    return SfxItemSet( rItemPool, svl::Items<
         SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,
-        SID_ATTR_NUMBERFORMAT_NOLANGUAGE, SID_ATTR_NUMBERFORMAT_NOLANGUAGE,
         SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA,
-        SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE,
-        0
-    };
-    return SfxItemSet( rItemPool, nWhichPairs );
+        SID_ATTR_NUMBERFORMAT_NOLANGUAGE, SID_ATTR_NUMBERFORMAT_NOLANGUAGE,
+        SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE>{} );
 }
 
 } //namespace chart
diff --git a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx
index ac08f2c99cf6..94d22f401d70 100644
--- a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx
+++ b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx
@@ -25,37 +25,36 @@
 
 #include <chartview/ChartSfxItemIds.hxx>
 
-#define CHARACTER_WHICHPAIRS \
-    EE_ITEMS_START, EE_ITEMS_END,  \
-    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING
-
 const sal_uInt16 nTitleWhichPairs[] =
 {
     SCHATTR_TEXT_START, SCHATTR_TEXT_END,
     XATTR_LINE_FIRST, XATTR_LINE_LAST,              //  1000 -  1016  svx/xdef.hxx
     XATTR_FILL_FIRST, XATTR_FILL_LAST,              //  1018 -  1046  svx/xdef.hxx
     SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,      //  1067 -  1078  svx/svddef.hxx
-    CHARACTER_WHICHPAIRS,
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
 const sal_uInt16 nAxisWhichPairs[] =
 {
+    SCHATTR_TEXT_START, SCHATTR_TEXT_END,
+    SCHATTR_AXIS_START, SCHATTR_AXIS_END,
     XATTR_LINE_FIRST, XATTR_LINE_LAST,                          //  1000 -  1016  svx/xdef.hxx
-    CHARACTER_WHICHPAIRS,
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
     SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE,   // 10585 - 10585  svx/svxids.hrc
     SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, // 11432          svx/svxids.hrc
-    SCHATTR_AXIS_START, SCHATTR_AXIS_END,
-    SCHATTR_TEXT_START, SCHATTR_TEXT_END,
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
 const sal_uInt16 nAllAxisWhichPairs[] =
 {
-    XATTR_LINE_FIRST, XATTR_LINE_LAST,
-    CHARACTER_WHICHPAIRS,
-    SCHATTR_AXIS_LABEL_START, SCHATTR_AXIS_LABEL_END,
     SCHATTR_TEXT_START, SCHATTR_TEXT_END,
+    SCHATTR_AXIS_LABEL_START, SCHATTR_AXIS_LABEL_END,
+    XATTR_LINE_FIRST, XATTR_LINE_LAST,
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
@@ -67,82 +66,86 @@ const sal_uInt16 nGridWhichPairs[] =
 
 const sal_uInt16 nLegendWhichPairs[] =
 {
+    SCHATTR_LEGEND_START, SCHATTR_LEGEND_END,       //     3 -     3  sch/schattr.hxx
     XATTR_LINE_FIRST, XATTR_LINE_LAST,              //  1000 -  1016  svx/xdef.hxx
     XATTR_FILL_FIRST, XATTR_FILL_LAST,              //  1018 -  1046  svx/xdef.hxx
     SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,      //  1067 -  1078  svx/svddef.hxx
-    CHARACTER_WHICHPAIRS,
-    SCHATTR_LEGEND_START, SCHATTR_LEGEND_END,       //     3 -     3  sch/schattr.hxx
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
 const sal_uInt16 nDataLabelWhichPairs[] =
 {
     SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END,
-    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,    /* 10585 - 10585  svx/svxids.hrc */
-    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432          svx/svxids.hrc */
     SCHATTR_TEXT_DEGREES,SCHATTR_TEXT_DEGREES,
     EE_PARA_WRITINGDIR,EE_PARA_WRITINGDIR,
+    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,    /* 10585 - 10585  svx/svxids.hrc */
+    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432          svx/svxids.hrc */
     0
 };
 
-#define CHART_POINT_WHICHPAIRS  \
-    XATTR_LINE_FIRST, XATTR_LINE_LAST,              /*  1000 -  1016  svx/xdef.hxx   */ \
-    XATTR_FILL_FIRST, XATTR_FILL_LAST,              /*  1018 -  1046  svx/xdef.hxx   */ \
-    EE_ITEMS_START, EE_ITEMS_END,                   /*  3994 -  4037  editeng/eeitem.hxx */ \
-    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, \
-    SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /*     1 -     2  sch/schattr.hxx*/ \
-    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,    /* 10585 - 10585  svx/svxids.hrc */ \
-    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432          svx/svxids.hrc */ \
-    SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, \
-    SCHATTR_STYLE_START,SCHATTR_STYLE_END,          /*    59 -    68  sch/schattr.hxx*/ \
-    SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH,      /*    94          sch/schattr.hxx*/ \
-    SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE,        /*    97          sch/schattr.hxx*/ \
-    SDRATTR_3D_FIRST, SDRATTR_3D_LAST,              /*  1244 -  1334  svx/svddef.hxx */ \
-    SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY
-
 const sal_uInt16 nDataPointWhichPairs[] =
 {
-    CHART_POINT_WHICHPAIRS,
+    SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /*     1 -     2  sch/schattr.hxx*/
+    SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES,
+    SCHATTR_STYLE_START,SCHATTR_STYLE_END,          /*    59 -    68  sch/schattr.hxx*/
+    SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH,      /*    94          sch/schattr.hxx*/
+    SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE,        /*    97          sch/schattr.hxx*/
+    SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY,
+    XATTR_LINE_FIRST, XATTR_LINE_LAST,              /*  1000 -  1016  svx/xdef.hxx   */
+    XATTR_FILL_FIRST, XATTR_FILL_LAST,              /*  1018 -  1046  svx/xdef.hxx   */
+    SDRATTR_3D_FIRST, SDRATTR_3D_LAST,              /*  1244 -  1334  svx/svddef.hxx */
+    EE_ITEMS_START, EE_ITEMS_END,                   /*  3994 -  4037  editeng/eeitem.hxx */
+    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,    /* 10585 - 10585  svx/svxids.hrc */
+    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432          svx/svxids.hrc */
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING,
     0
 };
 
 const sal_uInt16 nTextLabelWhichPairs[] =
 {
-    XATTR_LINESTYLE, XATTR_LINECOLOR,
-    XATTR_LINETRANSPARENCE, XATTR_LINETRANSPARENCE,
-    EE_ITEMS_START, EE_ITEMS_END,
-    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING,
     SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END,
-    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,
-    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE,
     SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES,
     SCHATTR_STYLE_SYMBOL, SCHATTR_STYLE_SYMBOL,
     SCHATTR_SYMBOL_BRUSH, SCHATTR_SYMBOL_BRUSH,
     SCHATTR_SYMBOL_SIZE, SCHATTR_SYMBOL_SIZE,
+    XATTR_LINESTYLE, XATTR_LINECOLOR,
+    XATTR_LINETRANSPARENCE, XATTR_LINETRANSPARENCE,
+    EE_ITEMS_START, EE_ITEMS_END,
+    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,
+    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE,
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING,
     0
 };
 
-#define CHART_SERIES_OPTIONS_WHICHPAIRS \
-    SCHATTR_AXIS,SCHATTR_AXIS,                      /*    69          sch/schattr.hxx*/ \
-    SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT,         /*    98 - 100 (incl. SCHATTR_GAPWIDTH) */  \
-    SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES, \
-    SCHATTR_STARTING_ANGLE,SCHATTR_STARTING_ANGLE, \
-    SCHATTR_CLOCKWISE,SCHATTR_CLOCKWISE, \
-    SCHATTR_MISSING_VALUE_TREATMENT,SCHATTR_MISSING_VALUE_TREATMENT, \
-    SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS,SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS, \
-    SCHATTR_INCLUDE_HIDDEN_CELLS,SCHATTR_INCLUDE_HIDDEN_CELLS, \
-    SCHATTR_HIDE_LEGEND_ENTRY,SCHATTR_HIDE_LEGEND_ENTRY
-
 const sal_uInt16 nSeriesOptionsWhichPairs[] =
 {
-    CHART_SERIES_OPTIONS_WHICHPAIRS,
+    SCHATTR_AXIS,SCHATTR_AXIS,                      /*    69          sch/schattr.hxx*/
+    SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT,         /*    98 - 100 (incl. SCHATTR_GAPWIDTH) */
+    SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES,
     0
 };
 
+// nDataPointWhichPairs + nSeriesOptionsWhichPairs
 const sal_uInt16 nRowWhichPairs[] =
 {
-    CHART_POINT_WHICHPAIRS,
-    CHART_SERIES_OPTIONS_WHICHPAIRS,
+    SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /*     1 -     2  sch/schattr.hxx*/
+    SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES,
+    SCHATTR_STYLE_START,SCHATTR_STYLE_END,          /*    59 -    68  sch/schattr.hxx*/
+    SCHATTR_AXIS,SCHATTR_AXIS,                      /*    69          sch/schattr.hxx*/
+    SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH,      /*    94          sch/schattr.hxx*/
+    SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE,        /*    97          sch/schattr.hxx*/
+    SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY,
+    SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT,         /*    98 - 100 (incl. SCHATTR_GAPWIDTH) */
+    SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES,
+    XATTR_LINE_FIRST, XATTR_LINE_LAST,              /*  1000 -  1016  svx/xdef.hxx   */
+    XATTR_FILL_FIRST, XATTR_FILL_LAST,              /*  1018 -  1046  svx/xdef.hxx   */
+    SDRATTR_3D_FIRST, SDRATTR_3D_LAST,              /*  1244 -  1334  svx/svddef.hxx */
+    EE_ITEMS_START, EE_ITEMS_END,                   /*  3994 -  4037  editeng/eeitem.hxx */
+    SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO,    /* 10585 - 10585  svx/svxids.hrc */
+    SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432          svx/svxids.hrc */
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING,
     0
 };
 
@@ -164,7 +167,8 @@ const sal_uInt16 nErrorBarWhichPairs[]=
 
 const sal_uInt16 nCharacterPropertyWhichPairs[] =
 {
-    CHARACTER_WHICHPAIRS,
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
@@ -194,8 +198,9 @@ const sal_uInt16 nRegEquationWhichPairs[] =
     XATTR_LINE_FIRST, XATTR_LINE_LAST,              //  1000 -  1016  svx/xdef.hxx
     XATTR_FILL_FIRST, XATTR_FILL_LAST,              //  1018 -  1046  svx/xdef.hxx
     SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,      //  1067 -  1078  svx/svddef.hxx
-    CHARACTER_WHICHPAIRS,
+    EE_ITEMS_START, EE_ITEMS_END,                             // Characters
     SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE,   // 10585 - 10585  svx/svxids.hrc
+    SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING, // Characters
     0
 };
 
diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx
index 94ee142a2e77..80d8ad5b4237 100644
--- a/include/svl/itemset.hxx
+++ b/include/svl/itemset.hxx
@@ -21,11 +21,13 @@
 
 #include <sal/config.h>
 
+#include <array>
 #include <cassert>
 #include <cstddef>
 #include <initializer_list>
 #include <type_traits>
 #include <memory>
+#include <utility>
 
 #include <svl/svldllapi.h>
 #include <svl/poolitem.hxx>
@@ -41,7 +43,7 @@ constexpr bool validRange(sal_uInt16 wid1, sal_uInt16 wid2)
 { return wid1 != 0 && wid1 <= wid2; }
 
 constexpr bool validGap(sal_uInt16 wid1, sal_uInt16 wid2)
-{ return wid2 > wid1 && wid2 - wid1 > 1; }
+{ return wid2 > wid1; }
 
 template<sal_uInt16 WID1, sal_uInt16 WID2> constexpr bool validRanges()
 { return validRange(WID1, WID2); }
@@ -52,6 +54,19 @@ constexpr bool validRanges() {
         && validRanges<WID3, WIDs...>();
 }
 
+inline constexpr bool validRanges(const sal_uInt16* pRanges)
+{
+    for (auto p = pRanges; p && *p; p += 2)
+    {
+        if (!validRange(p[0], p[1]))
+            return false;
+        // ranges must be sorted
+        if (p[2] != 0 && !validGap(p[1], p[2]))
+            return false;
+    }
+    return true;
+}
+
 // The calculations in rangeSize and rangesSize cannot overflow, assuming
 // std::size_t is no smaller than sal_uInt16:
 
@@ -71,6 +86,24 @@ constexpr std::size_t rangesSize()
 
 template<sal_uInt16... WIDs> struct Items {};
 
+// This allows creating compile-time which id arrays using syntax like
+//
+//     constexpr auto aWids = svl::ItemsArray({ { widFrom1, widTo2 }, { widFrom2, widTo2 }, ... });
+//
+// so that e.g. clang-format would not try to rearrange the initializer sequence to break pairs.
+// Additionally, the array validity is checked in debug builds.
+template <size_t N> constexpr auto ItemsArray(const std::pair<sal_uInt16, sal_uInt16> (&wids)[N])
+{
+    std::array<sal_uInt16, N * 2 + 1> aArray{};
+    sal_uInt16* p = aArray.data();
+    for (const auto& [wid1, wid2] : wids)
+    {
+        *p++ = wid1;
+        *p++ = wid2;
+    }
+    assert(svl::detail::validRanges(aArray.data()));
+    return aArray;
+}
 }
 
 class SAL_WARN_UNUSED SVL_DLLPUBLIC SfxItemSet
@@ -88,7 +121,7 @@ friend class SfxItemPoolCache;
 friend class SfxAllItemSet;
 
 private:
-    SVL_DLLPRIVATE void                     InitRanges_Impl(const sal_uInt16 *nWhichPairTable);
+    SVL_DLLPRIVATE sal_uInt16 InitRanges_Impl(const sal_uInt16 *nWhichPairTable);
 
     SfxItemSet(
         SfxItemPool & pool, std::initializer_list<sal_uInt16> wids,
@@ -248,8 +281,6 @@ class SVL_DLLPUBLIC SfxAllItemSet: public SfxItemSet
 //  Handles all Ranges. Ranges are automatically modified by putting items.
 
 {
-    sal_uInt16                      nFree;
-
 public:
                                 SfxAllItemSet( SfxItemPool &rPool );
                                 SfxAllItemSet( const SfxItemSet & );
diff --git a/sc/source/ui/dbgui/validate.cxx b/sc/source/ui/dbgui/validate.cxx
index 0ee9b69ab83a..ddd09086f144 100644
--- a/sc/source/ui/dbgui/validate.cxx
+++ b/sc/source/ui/dbgui/validate.cxx
@@ -80,8 +80,8 @@ namespace ValidListType = css::sheet::TableValidationVisibility;
 
 const sal_uInt16 ScTPValidationValue::pValueRanges[] =
 {
-    FID_VALID_MODE, FID_VALID_ERRTEXT,
     FID_VALID_LISTTYPE, FID_VALID_LISTTYPE,
+    FID_VALID_MODE, FID_VALID_ERRTEXT,
     0
 };
 
diff --git a/sd/source/ui/func/fupage.cxx b/sd/source/ui/func/fupage.cxx
index 6d44b70d5a9d..6adf302d5607 100644
--- a/sd/source/ui/func/fupage.cxx
+++ b/sd/source/ui/func/fupage.cxx
@@ -200,15 +200,17 @@ const SfxItemSet* FuPage::ExecuteDialog(weld::Window* pParent, const SfxRequest&
     if (!mpDrawViewShell)
         return nullptr;
 
-    SfxItemSet aNewAttr(mpDoc->GetPool(),
-                        {{mpDoc->GetPool().GetWhich(SID_ATTR_LRSPACE),
-                        mpDoc->GetPool().GetWhich(SID_ATTR_ULSPACE)},
-                        {SID_ATTR_PAGE, SID_ATTR_PAGE_SHARED},
-                        {SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER},
-                        {SID_ATTR_BORDER_SHADOW, SID_ATTR_BORDER_SHADOW},
-                        {XATTR_FILL_FIRST, XATTR_FILL_LAST},
-                        {SID_ATTR_PAGE_COLOR,SID_ATTR_PAGE_FILLSTYLE},
-                        {EE_PARA_WRITINGDIR, EE_PARA_WRITINGDIR}});
+    SfxItemSet aNewAttr(mpDoc->GetPool(), {
+                                              { XATTR_FILL_FIRST, XATTR_FILL_LAST },
+                                              { EE_PARA_WRITINGDIR, EE_PARA_WRITINGDIR },
+                                              { SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER },
+                                              { SID_ATTR_BORDER_SHADOW, SID_ATTR_BORDER_SHADOW },
+                                              { SID_ATTR_PAGE, SID_ATTR_PAGE_SHARED },
+                                              { SID_ATTR_PAGE_COLOR, SID_ATTR_PAGE_FILLSTYLE },
+                                          });
+    // Keep it sorted
+    aNewAttr.MergeRange(mpDoc->GetPool().GetWhich(SID_ATTR_LRSPACE),
+                        mpDoc->GetPool().GetWhich(SID_ATTR_ULSPACE));
 
     // Retrieve additional data for dialog
 
diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx
index d648fdf87537..1792e330f5c4 100644
--- a/sfx2/source/control/bindings.cxx
+++ b/sfx2/source/control/bindings.cxx
@@ -1162,21 +1162,18 @@ std::unique_ptr<SfxItemSet> SfxBindings::CreateSet_Impl
     }
 
     // Create a Set from the ranges
-    std::unique_ptr<sal_uInt16[]> pRanges(new sal_uInt16[rFound.size() * 2 + 1]);
-    int j = 0;
     size_t i = 0;
+    auto pSet(std::make_unique<SfxItemSet>(rPool, nullptr));
     while ( i < rFound.size() )
     {
-        pRanges[j++] = rFound[i].nWhichId;
+        const sal_uInt16 nWhich1 = rFound[i].nWhichId;
             // consecutive numbers
         for ( ; i < rFound.size()-1; ++i )
             if ( rFound[i].nWhichId+1 != rFound[i+1].nWhichId )
                 break;
-        pRanges[j++] = rFound[i++].nWhichId;
+        const sal_uInt16 nWhich2 = rFound[i++].nWhichId;
+        pSet->MergeRange(nWhich1, nWhich2);
     }
-    pRanges[j] = 0; // terminating NULL
-    std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(rPool, pRanges.get()));
-    pRanges.reset();
     return pSet;
 }
 
diff --git a/sfx2/source/dialog/tabdlg.cxx b/sfx2/source/dialog/tabdlg.cxx
index 484b431a690e..c18139dbc347 100644
--- a/sfx2/source/dialog/tabdlg.cxx
+++ b/sfx2/source/dialog/tabdlg.cxx
@@ -687,7 +687,7 @@ const sal_uInt16* SfxTabDialogController::GetInputRanges(const SfxItemPool& rPoo
 
     if ( m_pRanges )
         return m_pRanges.get();
-    std::vector<sal_uInt16> aUS;
+    SfxItemSet aUS(const_cast<SfxItemPool&>(rPool));
 
     for (auto const& elem : m_pImpl->aData)
     {
@@ -695,30 +695,24 @@ const sal_uInt16* SfxTabDialogController::GetInputRanges(const SfxItemPool& rPoo
         if ( elem->fnGetRanges )
         {
             const sal_uInt16* pTmpRanges = (elem->fnGetRanges)();
-            const sal_uInt16* pIter = pTmpRanges;
 
-            sal_uInt16 nLen;
-            for( nLen = 0; *pIter; ++nLen, ++pIter )
-                ;
-            aUS.insert( aUS.end(), pTmpRanges, pTmpRanges + nLen );
+            for (const sal_uInt16* pIter = pTmpRanges; *pIter;)
+            {
+                sal_uInt16 nWidFrom = rPool.GetWhich(*pIter++);
+                assert(*pIter);
+                sal_uInt16 nWidTo = rPool.GetWhich(*pIter++);
+                aUS.MergeRange(nWidFrom, nWidTo); // Keep it valid
+            }
         }
     }
 
-    //! Remove duplicated Ids?
-    {
-        for (auto & elem : aUS)
-            elem = rPool.GetWhich(elem);
-    }
-
-    // sort
-    if ( aUS.size() > 1 )
-    {
-        std::sort( aUS.begin(), aUS.end() );
-    }
+    int nSize = 0;
+    for (const sal_uInt16* pIter = aUS.GetRanges(); pIter && *pIter; pIter++)
+        ++nSize;
 
-    m_pRanges.reset(new sal_uInt16[aUS.size() + 1]);
-    std::copy( aUS.begin(), aUS.end(), m_pRanges.get() );
-    m_pRanges[aUS.size()] = 0;
+    m_pRanges.reset(new sal_uInt16[nSize + 1]);
+    std::copy(aUS.GetRanges(), aUS.GetRanges() + nSize, m_pRanges.get());
+    m_pRanges[nSize] = 0;
     return m_pRanges.get();
 }
 
diff --git a/starmath/source/unomodel.cxx b/starmath/source/unomodel.cxx
index 623fad785844..7628768ae50b 100644
--- a/starmath/source/unomodel.cxx
+++ b/starmath/source/unomodel.cxx
@@ -607,19 +607,15 @@ void SmModel::_setPropertyValues(const PropertyMapEntry** ppEntries, const Any*
                 sal_uInt32 nSize = aSequence.getLength();
                 SvMemoryStream aStream ( aSequence.getArray(), nSize, StreamMode::READ );
                 aStream.Seek ( STREAM_SEEK_TO_BEGIN );
-                static sal_uInt16 const nRange[] =
-                {
-                    SID_PRINTSIZE,       SID_PRINTSIZE,
-                    SID_PRINTZOOM,       SID_PRINTZOOM,
+                auto pItemSet = std::make_unique<SfxItemSet>( SmDocShell::GetPool(), svl::Items<
                     SID_PRINTTITLE,      SID_PRINTTITLE,
                     SID_PRINTTEXT,       SID_PRINTTEXT,
                     SID_PRINTFRAME,      SID_PRINTFRAME,
+                    SID_PRINTSIZE,       SID_PRINTSIZE,
+                    SID_PRINTZOOM,       SID_PRINTZOOM,
                     SID_NO_RIGHT_SPACES, SID_NO_RIGHT_SPACES,
                     SID_SAVE_ONLY_USED_SYMBOLS, SID_SAVE_ONLY_USED_SYMBOLS,
-                    SID_AUTO_CLOSE_BRACKETS,    SID_AUTO_CLOSE_BRACKETS,
-                    0
-                };
-                auto pItemSet = std::make_unique<SfxItemSet>( SmDocShell::GetPool(), nRange );
+                    SID_AUTO_CLOSE_BRACKETS,    SID_AUTO_CLOSE_BRACKETS>{} );
                 SmModule *pp = SM_MOD();
                 pp->GetConfig()->ConfigToItemSet(*pItemSet);
                 VclPtr<SfxPrinter> pPrinter = SfxPrinter::Create ( aStream, std::move(pItemSet) );
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 6deec84947c0..c6fcd488265d 100644
--- a/svl/source/items/itempool.cxx
+++ b/svl/source/items/itempool.cxx
@@ -28,6 +28,8 @@
 #include <svl/SfxBroadcaster.hxx>
 #include <svl/hint.hxx>
 #include <svl/itemset.hxx>
+
+#include <items_helper.hxx>
 #include <poolio.hxx>
 
 #include <algorithm>
@@ -795,20 +797,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 )
-        ++nLevel;
-
-    pWhichRanges.reset(new sal_uInt16[ 2*nLevel + 1 ]);
+    pWhichRanges.reset();
 
-    nLevel = 0;
-    for( pPool = this; pPool; pPool = pPool->pImpl->mpSecondary )
-    {
-        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)
+        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 8d7b1e463911..d4e808463f71 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 );
 }
 
 /**
@@ -1514,19 +1400,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)
 {
 }
 
@@ -1535,66 +1414,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);
 }
 
 /**
@@ -1602,122 +1423,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);
 }
 
 /**
diff --git a/svx/source/dialog/hdft.cxx b/svx/source/dialog/hdft.cxx
index 06605ce2efcf..de65ff6c5d01 100644
--- a/svx/source/dialog/hdft.cxx
+++ b/svx/source/dialog/hdft.cxx
@@ -202,30 +202,25 @@ bool SvxHFPage::FillItemSet( SfxItemSet* rSet )
     const sal_uInt16 nWBoxInfo = GetWhich(SID_ATTR_BORDER_INNER);
     const sal_uInt16 nWShadow = GetWhich(SID_ATTR_BORDER_SHADOW);
 
-    const sal_uInt16 aWhichTab[] = {
-        nWSize, nWSize,
-        nWLRSpace, nWLRSpace,
-        nWULSpace, nWULSpace,
-        nWOn, nWOn,
-        nWDynamic, nWDynamic,
-        nWShared, nWShared,
-        nWSharedFirst, nWSharedFirst,
-        nWBrush, nWBrush,
-        nWBoxInfo, nWBoxInfo,
-        nWBox, nWBox,
-        nWShadow, nWShadow,
-        nWDynSpacing, nWDynSpacing,
-
-        // take over DrawingLayer FillStyles
-        XATTR_FILL_FIRST, XATTR_FILL_LAST,                // [1014
-
-        0, 0};
-
     const SfxItemSet& rOldSet = GetItemSet();
     SfxItemPool* pPool = rOldSet.GetPool();
     DBG_ASSERT(pPool,"no pool :-(");
     MapUnit eUnit = pPool->GetMetric(nWSize);
-    SfxItemSet aSet(*pPool,aWhichTab);
+    // take over DrawingLayer FillStyles
+    SfxItemSet aSet(*pPool, svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>{});
+    // Keep it valid
+    aSet.MergeRange(nWSize, nWSize);
+    aSet.MergeRange(nWLRSpace, nWLRSpace);
+    aSet.MergeRange(nWULSpace, nWULSpace);
+    aSet.MergeRange(nWOn, nWOn);
+    aSet.MergeRange(nWDynamic, nWDynamic);
+    aSet.MergeRange(nWShared, nWShared);
+    aSet.MergeRange(nWSharedFirst, nWSharedFirst);
+    aSet.MergeRange(nWBrush, nWBrush);
+    aSet.MergeRange(nWBoxInfo, nWBoxInfo);
+    aSet.MergeRange(nWBox, nWBox);
+    aSet.MergeRange(nWShadow, nWShadow);
+    aSet.MergeRange(nWDynSpacing, nWDynSpacing);
 
     if(mbEnableDrawingLayerFillStyles)
     {
@@ -540,11 +535,12 @@ IMPL_LINK_NOARG(SvxHFPage, BackgroundHdl, weld::Button&, void)
         {
             pBBSet.reset(new SfxItemSet(
                 *GetItemSet().GetPool(),
-                {{XATTR_FILL_FIRST, XATTR_FILL_LAST},  // DrawingLayer FillStyle definitions
-                {SID_COLOR_TABLE, SID_PATTERN_LIST},   // XPropertyLists for Color, Gradient, Hatch and Graphic fills
-                {nOuter, nOuter},
-                {nInner, nInner},
-                {nShadow, nShadow}}));
+                svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST,      // DrawingLayer FillStyle definitions
+                           SID_COLOR_TABLE, SID_PATTERN_LIST>{})); // XPropertyLists for Color, Gradient, Hatch and Graphic fills
+            // Keep it valid
+            pBBSet->MergeRange(nOuter, nOuter);
+            pBBSet->MergeRange(nInner, nInner);
+            pBBSet->MergeRange(nShadow, nShadow);
 
             // copy items for XPropertyList entries from the DrawModel so that
             // the Area TabPage can access them
@@ -577,11 +573,12 @@ IMPL_LINK_NOARG(SvxHFPage, BackgroundHdl, weld::Button&, void)
 
             pBBSet.reset( new SfxItemSet(
                 *GetItemSet().GetPool(),
-                {{XATTR_FILL_FIRST, XATTR_FILL_LAST},
-                {nBrush, nBrush},
-                {nOuter, nOuter},
-                {nInner, nInner},
-                {nShadow, nShadow}}) );
+                svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>{}) );
+            // Keep it valid
+            pBBSet->MergeRange(nBrush, nBrush);
+            pBBSet->MergeRange(nOuter, nOuter);
+            pBBSet->MergeRange(nInner, nInner);
+            pBBSet->MergeRange(nShadow, nShadow);
         }
 
         const SfxPoolItem* pItem;
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 58d8437b9513..1bf140367ac1 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -2629,25 +2629,21 @@ bool SdrObjEditView::SupportsFormatPaintbrush(SdrInventor nObjectInventor,
 
 static const sal_uInt16* GetFormatRangeImpl(bool bTextOnly)
 {
-    static const sal_uInt16 gRanges[] = { SDRATTR_SHADOW_FIRST,
-                                          SDRATTR_SHADOW_LAST,
-                                          SDRATTR_GRAF_FIRST,
-                                          SDRATTR_GRAF_LAST,
-                                          SDRATTR_TABLE_FIRST,
-                                          SDRATTR_TABLE_LAST,
-                                          XATTR_LINE_FIRST,
-                                          XATTR_LINE_LAST,
-                                          XATTR_FILL_FIRST,
-                                          XATTRSET_FILL,
-                                          EE_PARA_START,
-                                          EE_PARA_END, // text-only from here on
-                                          EE_CHAR_START,
-                                          EE_CHAR_END,
-                                          SDRATTR_MISC_FIRST,
-                                          SDRATTR_MISC_LAST, // table cell formats
-                                          0,
-                                          0 };
-    return &gRanges[bTextOnly ? 10 : 0];
+    static constexpr auto gFull
+        = svl::ItemsArray({ { XATTR_LINE_FIRST, XATTR_LINE_LAST },
+                            { XATTR_FILL_FIRST, XATTRSET_FILL },
+                            { SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST },
+                            { SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST }, // table cell formats
+                            { SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST },
+                            { SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST },
+                            { EE_PARA_START, EE_PARA_END },
+                            { EE_CHAR_START, EE_CHAR_END } });
+
+    static constexpr auto gTextOnly = svl::ItemsArray({ { SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST },
+                                                        { EE_PARA_START, EE_PARA_END },
+                                                        { EE_CHAR_START, EE_CHAR_END } });
+
+    return bTextOnly ? gTextOnly.data() : gFull.data();
 }
 
 void SdrObjEditView::TakeFormatPaintBrush(std::shared_ptr<SfxItemSet>& rFormatSet)
diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index 1d59814cd810..cb7de9e860e0 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -147,9 +147,9 @@ sal_uInt16 const aBreakSetRange[] = {
 // list attributes ( RES_PARATR_LIST_BEGIN - RES_PARATR_LIST_END ) are not
 // included in the paragraph style's itemset.
 sal_uInt16 const aTextFormatCollSetRange[] = {
-    RES_FRMATR_BEGIN, RES_FRMATR_END-1,
     RES_CHRATR_BEGIN, RES_CHRATR_END-1,
     RES_PARATR_BEGIN, RES_PARATR_END-1,
+    RES_FRMATR_BEGIN, RES_FRMATR_END-1,
     RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
 
     // FillAttribute support
@@ -168,10 +168,10 @@ sal_uInt16 const aGrfFormatCollSetRange[] = {
 
 // AttrSet range for TextNode
 sal_uInt16 const aTextNodeSetRange[] = {
-    RES_FRMATR_BEGIN, RES_FRMATR_END-1,
     RES_CHRATR_BEGIN, RES_CHRATR_END-1,
     RES_PARATR_BEGIN, RES_PARATR_END-1,
     RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
+    RES_FRMATR_BEGIN, RES_FRMATR_END-1,
     RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
 
     // FillAttribute support (paragraph FillStyle)
@@ -191,41 +191,41 @@ sal_uInt16 const aNoTextNodeSetRange[] = {
 sal_uInt16 const aTableSetRange[] = {
     RES_FILL_ORDER,     RES_FRM_SIZE,
     RES_LR_SPACE,       RES_BREAK,
-    RES_BACKGROUND,     RES_SHADOW,
     RES_HORI_ORIENT,    RES_HORI_ORIENT,
+    RES_BACKGROUND,     RES_SHADOW,
     RES_KEEP,           RES_KEEP,
     RES_LAYOUT_SPLIT,   RES_LAYOUT_SPLIT,
     RES_FRAMEDIR,       RES_FRAMEDIR,
     // #i29550#
     RES_COLLAPSING_BORDERS, RES_COLLAPSING_BORDERS,
     // <-- collapsing
-    RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
     RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG,
+    RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
     0
 };
 
 sal_uInt16 const aTableLineSetRange[] = {
     RES_FILL_ORDER,     RES_FRM_SIZE,
     RES_LR_SPACE,       RES_UL_SPACE,
-    RES_BACKGROUND,     RES_SHADOW,
-    RES_ROW_SPLIT,      RES_ROW_SPLIT,
     RES_PROTECT,        RES_PROTECT,
     RES_VERT_ORIENT,    RES_VERT_ORIENT,
-    RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+    RES_BACKGROUND,     RES_SHADOW,
+    RES_ROW_SPLIT,      RES_ROW_SPLIT,
     RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG,
+    RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
     0
 };
 
 sal_uInt16 const aTableBoxSetRange[] = {
     RES_FILL_ORDER,     RES_FRM_SIZE,
     RES_LR_SPACE,       RES_UL_SPACE,
-    RES_BACKGROUND,     RES_SHADOW,
     RES_PROTECT,        RES_PROTECT,
     RES_VERT_ORIENT,    RES_VERT_ORIENT,
+    RES_BACKGROUND,     RES_SHADOW,
     RES_FRAMEDIR,       RES_FRAMEDIR,
+    RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG,
     RES_BOXATR_BEGIN,   RES_BOXATR_END-1,
     RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
-    RES_FRMATR_GRABBAG, RES_FRMATR_GRABBAG,
     0
 };
 
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 3380b5e6bc15..bee045a5757c 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -842,10 +842,10 @@ void SwDoc::ReplaceDefaults(const SwDoc& rSource)
     // copy property defaults
     const sal_uInt16 aRangeOfDefaults[] =
     {
-        RES_FRMATR_BEGIN, RES_FRMATR_END-1,
         RES_CHRATR_BEGIN, RES_CHRATR_END-1,
         RES_PARATR_BEGIN, RES_PARATR_END-1,
         RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
+        RES_FRMATR_BEGIN, RES_FRMATR_END-1,
         RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
         XATTR_START, XATTR_END-1,
         0
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index acca43916522..f30ebce4c0f8 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -3044,15 +3044,11 @@ void sw_BoxSetSplitBoxFormats( SwTableBox* pBox, SwCollectTableLineBoxes* pSplPa
         }
         else
         {
-            sal_uInt16 const aTableSplitBoxSetRange[] {
-                RES_LR_SPACE,       RES_UL_SPACE,
-                RES_BACKGROUND,     RES_SHADOW,
-                RES_PROTECT,        RES_PROTECT,
-                RES_VERT_ORIENT,    RES_VERT_ORIENT,
-                0 };
-
             SfxItemSet aTmpSet( pFormat->GetDoc()->GetAttrPool(),
-                                aTableSplitBoxSetRange );
+                                svl::Items<RES_LR_SPACE,    RES_UL_SPACE,
+                                           RES_PROTECT,     RES_PROTECT,
+                                           RES_VERT_ORIENT, RES_VERT_ORIENT,
+                                           RES_BACKGROUND,  RES_SHADOW>{} );
             aTmpSet.Put( pFormat->GetAttrSet() );
             if( aTmpSet.Count() )
                 pBox->ClaimFrameFormat()->SetFormatAttr( aTmpSet );
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
index 0e486a2963e1..4825335540b8 100644
--- a/sw/source/core/fields/expfld.cxx
+++ b/sw/source/core/fields/expfld.cxx
@@ -983,13 +983,13 @@ sal_Int32 SwGetExpField::GetReferenceTextPos( const SwFormatField& rFormat, SwDo
 
         static const sal_uInt16 nIds[] =
         {
-            RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
             RES_CHRATR_FONT, RES_CHRATR_FONT,
-            RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
+            RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
             RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONT,
-            RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
+            RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
             RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONT,
-            0, 0
+            RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
+            0
         };
         SwAttrSet aSet(rDoc.GetAttrPool(), nIds);
         rTextNode.GetParaAttr(aSet, nRet, nRet+1);
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 61e1101fb330..82325abed03a 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1070,15 +1070,10 @@ void SwTextNode::SetLanguageAndFont( const SwPaM &rPaM,
     LanguageType nLang, sal_uInt16 nLangWhichId,
     const vcl::Font *pFont,  sal_uInt16 nFontWhichId )
 {
-    sal_uInt16 aRanges[] = {
-            nLangWhichId, nLangWhichId,
-            nFontWhichId, nFontWhichId,
-            0, 0, 0 };
-    if (!pFont)
-        aRanges[2] = aRanges[3] = 0;    // clear entries with font WhichId
-
     SwEditShell *pEditShell = GetDoc().GetEditShell();
-    SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
+    SfxItemSet aSet(pEditShell->GetAttrPool(), { { nLangWhichId, nLangWhichId } });
+    if (pFont)
+        aSet.MergeRange(nFontWhichId, nFontWhichId); // Keep it sorted
     aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
 
     OSL_ENSURE( pFont, "target font missing?" );
diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx
index 8c09a63113fa..e7a5944427dc 100644
--- a/sw/source/core/unocore/unocrsrhelper.cxx
+++ b/sw/source/core/unocore/unocrsrhelper.cxx
@@ -1293,7 +1293,7 @@ void makeRedline( SwPaM const & rPaM,
             SwDoc& rDoc = rPaM.GetDoc();
 
             // Build set of attributes we want to fetch
-            std::vector<sal_uInt16> aWhichPairs;
+            std::vector<std::pair<sal_uInt16, sal_uInt16>> aWhichPairs;
             std::vector<SfxItemPropertySimpleEntry const*> aEntries;
             std::vector<uno::Any> aValues;
             aEntries.reserve(aRevertProperties.getLength());
@@ -1315,15 +1315,12 @@ void makeRedline( SwPaM const & rPaM,
                 }
                 else if (rPropertyName == "NumberingRules")
                 {
-                    aWhichPairs.push_back(RES_PARATR_NUMRULE);
-                    aWhichPairs.push_back(RES_PARATR_NUMRULE);
+                    aWhichPairs.emplace_back(RES_PARATR_NUMRULE, RES_PARATR_NUMRULE);
                     nNumId = aEntries.size();
                 }
                 else
                 {
-                    // FIXME: we should have some nice way of merging ranges surely ?
-                    aWhichPairs.push_back(pEntry->nWID);
-                    aWhichPairs.push_back(pEntry->nWID);
+                    aWhichPairs.emplace_back(pEntry->nWID, pEntry->nWID);
                     if (rPropertyName == "ParaStyleName")
                         nStyleId = aEntries.size();
                 }
@@ -1335,8 +1332,9 @@ void makeRedline( SwPaM const & rPaM,
             {
                 sal_uInt16 nStylePoolId = USHRT_MAX;
                 OUString sParaStyleName;
-                aWhichPairs.push_back(0); // terminate
-                SfxItemSet aItemSet(rDoc.GetAttrPool(), aWhichPairs.data());
+                SfxItemSet aItemSet(rDoc.GetAttrPool(), nullptr);
+                for (const auto& [nWhich1, nWhich2] : aWhichPairs)
+                    aItemSet.MergeRange(nWhich1, nWhich2);
 
                 for (size_t i = 0; i < aEntries.size(); ++i)
                 {
diff --git a/sw/source/uibase/app/docshini.cxx b/sw/source/uibase/app/docshini.cxx
index f4aadf7476ca..5700c643508c 100644
--- a/sw/source/uibase/app/docshini.cxx
+++ b/sw/source/uibase/app/docshini.cxx
@@ -624,11 +624,11 @@ void SwDocShell::SubInitNew()
     bool bWeb = dynamic_cast< const SwWebDocShell *>( this ) !=  nullptr;
 
     sal_uInt16 nRange[] =   {
-        RES_PARATR_ADJUST, RES_PARATR_ADJUST,
         RES_CHRATR_COLOR, RES_CHRATR_COLOR,
         RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
         RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
         RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
+        RES_PARATR_ADJUST, RES_PARATR_ADJUST,
         0, 0, 0  };
     if(!bWeb)
     {
diff --git a/sw/source/uibase/lingu/hhcwrp.cxx b/sw/source/uibase/lingu/hhcwrp.cxx
index 23974dfa109a..f724ed377119 100644
--- a/sw/source/uibase/lingu/hhcwrp.cxx
+++ b/sw/source/uibase/lingu/hhcwrp.cxx
@@ -466,12 +466,9 @@ void SwHHCWrapper::ReplaceUnit(
             OSL_ENSURE( GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED || GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL,
                     "SwHHCWrapper::ReplaceUnit : unexpected target language" );
 
-            sal_uInt16 const aRanges[] {
-                    RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
+            SfxItemSet aSet( m_rWrtShell.GetAttrPool(), svl::Items<
                     RES_CHRATR_CJK_FONT,     RES_CHRATR_CJK_FONT,
-                    0, 0, 0  };
-
-            SfxItemSet aSet( m_rWrtShell.GetAttrPool(), aRanges );
+                    RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE>{} );
             if (pNewUnitLanguage)
             {
                 aSet.Put( SvxLanguageItem( *pNewUnitLanguage, RES_CHRATR_CJK_LANGUAGE ) );
diff --git a/sw/source/uibase/shells/tabsh.cxx b/sw/source/uibase/shells/tabsh.cxx
index 82c382b6fe36..c0c4d58d5690 100644
--- a/sw/source/uibase/shells/tabsh.cxx
+++ b/sw/source/uibase/shells/tabsh.cxx
@@ -95,29 +95,29 @@ void SwTableShell::InitInterface_Impl()
 
 const sal_uInt16 aUITableAttrRange[] =
 {
-    XATTR_FILL_FIRST,               XATTR_FILL_LAST,
-    FN_PARAM_TABLE_NAME,            FN_PARAM_TABLE_NAME,
-    FN_PARAM_TABLE_HEADLINE,        FN_PARAM_TABLE_HEADLINE,
-    FN_PARAM_TABLE_SPACE,           FN_PARAM_TABLE_SPACE,
-    FN_TABLE_REP,                   FN_TABLE_REP,
-    SID_RULER_BORDERS,              SID_RULER_BORDERS,
     RES_LR_SPACE,                   RES_UL_SPACE,
-    SID_ATTR_BORDER_INNER,          SID_ATTR_BORDER_SHADOW,
-    RES_BOX,                        RES_SHADOW,
-    RES_BACKGROUND,                 RES_BACKGROUND,
-    SID_BACKGRND_DESTINATION,       SID_BACKGRND_DESTINATION,
-    SID_HTML_MODE,                  SID_HTML_MODE,
-    SID_ATTR_BRUSH_ROW,             SID_ATTR_BRUSH_TABLE,
     RES_PAGEDESC,                   RES_BREAK,
+    RES_BACKGROUND,                 RES_BACKGROUND,
+    RES_BOX,                        RES_SHADOW,
     RES_KEEP,                       RES_KEEP,
     RES_LAYOUT_SPLIT,               RES_LAYOUT_SPLIT,
-    FN_TABLE_SET_VERT_ALIGN,        FN_TABLE_SET_VERT_ALIGN,
     RES_FRAMEDIR,                   RES_FRAMEDIR,
     RES_ROW_SPLIT,                  RES_ROW_SPLIT,
-    FN_TABLE_BOX_TEXTORIENTATION,   FN_TABLE_BOX_TEXTORIENTATION,
 // #i29550#
     RES_COLLAPSING_BORDERS,         RES_COLLAPSING_BORDERS,
 // <-- collapsing borders
+    XATTR_FILL_FIRST,               XATTR_FILL_LAST,
+    SID_ATTR_BORDER_INNER,          SID_ATTR_BORDER_SHADOW,
+    SID_RULER_BORDERS,              SID_RULER_BORDERS,
+    SID_ATTR_BRUSH_ROW,             SID_ATTR_BRUSH_TABLE, // ??? This is very strange range
+//  SID_BACKGRND_DESTINATION,       SID_BACKGRND_DESTINATION, // included into above
+//  SID_HTML_MODE,                  SID_HTML_MODE, // included into above
+    FN_TABLE_REP,                   FN_TABLE_REP,
+    FN_TABLE_SET_VERT_ALIGN,        FN_TABLE_SET_VERT_ALIGN,
+    FN_TABLE_BOX_TEXTORIENTATION,   FN_TABLE_BOX_TEXTORIENTATION,
+    FN_PARAM_TABLE_NAME,            FN_PARAM_TABLE_NAME,
+    FN_PARAM_TABLE_HEADLINE,        FN_PARAM_TABLE_HEADLINE,
+    FN_PARAM_TABLE_SPACE,           FN_PARAM_TABLE_SPACE,
     0
 };
 
diff --git a/sw/source/uibase/shells/textsh.cxx b/sw/source/uibase/shells/textsh.cxx
index daa913816a63..9c942b7858cd 100644
--- a/sw/source/uibase/shells/textsh.cxx
+++ b/sw/source/uibase/shells/textsh.cxx
@@ -836,20 +836,15 @@ SwTextShell::~SwTextShell()
 
 SfxItemSet SwTextShell::CreateInsertFrameItemSet(SwFlyFrameAttrMgr& rMgr)
 {
-    static const sal_uInt16 aFrameAttrRange[] =
-    {
+    SfxItemSet aSet(GetPool(), svl::Items<
         RES_FRMATR_BEGIN,       RES_FRMATR_END-1,
+        XATTR_FILL_FIRST,       XATTR_FILL_LAST, // tdf#95003
         SID_ATTR_BORDER_INNER,  SID_ATTR_BORDER_INNER,
-        FN_GET_PRINT_AREA,      FN_GET_PRINT_AREA,
         SID_ATTR_PAGE_SIZE,     SID_ATTR_PAGE_SIZE,
-        FN_SET_FRM_NAME,        FN_SET_FRM_NAME,
-        SID_HTML_MODE,          SID_HTML_MODE,
         SID_COLOR_TABLE,        SID_PATTERN_LIST,
-        XATTR_FILL_FIRST,       XATTR_FILL_LAST, // tdf#95003
-        0
-    };
-
-    SfxItemSet aSet(GetPool(), aFrameAttrRange );
+        SID_HTML_MODE,          SID_HTML_MODE,
+        FN_GET_PRINT_AREA,      FN_GET_PRINT_AREA,
+        FN_SET_FRM_NAME,        FN_SET_FRM_NAME>{});
     aSet.Put(SfxUInt16Item(SID_HTML_MODE, ::GetHtmlMode(GetView().GetDocShell())));
 
     // For the Area tab page.
diff --git a/sw/source/uibase/uiview/viewsrch.cxx b/sw/source/uibase/uiview/viewsrch.cxx
index 578d02f296d4..a0cd2967fad5 100644
--- a/sw/source/uibase/uiview/viewsrch.cxx
+++ b/sw/source/uibase/uiview/viewsrch.cxx
@@ -740,9 +740,9 @@ sal_uLong SwView::FUNC_Search( const SwSearchOptions& rOptions )
     m_pWrtShell->SttSelect();
 
     static const sal_uInt16 aSearchAttrRange[] = {
-        RES_FRMATR_BEGIN, RES_FRMATR_END-1,
         RES_CHRATR_BEGIN, RES_CHRATR_END-1,
         RES_PARATR_BEGIN, RES_PARATR_END-1,
+        RES_FRMATR_BEGIN, RES_FRMATR_END-1,
         SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
         0 };
 
diff --git a/sw/source/uibase/uno/SwXDocumentSettings.cxx b/sw/source/uibase/uno/SwXDocumentSettings.cxx
index 19dabb9ea6b8..2643071e13dd 100644
--- a/sw/source/uibase/uno/SwXDocumentSettings.cxx
+++ b/sw/source/uibase/uno/SwXDocumentSettings.cxx
@@ -449,15 +449,11 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf
                 SvMemoryStream aStream (aSequence.getArray(), nSize,
                                         StreamMode::READ );
                 aStream.Seek ( STREAM_SEEK_TO_BEGIN );
-                static sal_uInt16 const nRange[] =
-                {
-                    FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER,
-                    SID_HTML_MODE,  SID_HTML_MODE,
+                auto pItemSet = std::make_unique<SfxItemSet>( mpDoc->GetAttrPool(), svl::Items<
                     SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
                     SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
-                    0
-                };
-                auto pItemSet = std::make_unique<SfxItemSet>( mpDoc->GetAttrPool(), nRange );
+                    SID_HTML_MODE,  SID_HTML_MODE,
+                    FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER>{} );
                 VclPtr<SfxPrinter> pPrinter = SfxPrinter::Create ( aStream, std::move(pItemSet) );
                 assert (! pPrinter->isDisposed() );
                 // set printer only once; in _postSetValues


More information about the Libreoffice-commits mailing list