diff options
Diffstat (limited to 'svl/source/inc/items_helper.hxx')
-rw-r--r-- | svl/source/inc/items_helper.hxx | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/svl/source/inc/items_helper.hxx b/svl/source/inc/items_helper.hxx new file mode 100644 index 000000000000..75582d9f8741 --- /dev/null +++ b/svl/source/inc/items_helper.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <sal/types.h> +#include <svl/itemset.hxx> + +#include <memory> +#include <utility> +#include <vector> + +namespace svl::detail +{ +/** + * Determines the number of sal_uInt16s in a 0-terminated array of pairs of + * sal_uInt16s, each representing a range of sal_uInt16s, and total capacity of the ranges. + * The terminating 0 is included in the count. + */ +inline std::pair<sal_uInt16, sal_uInt16> CountRanges(const sal_uInt16* pRanges) +{ + sal_uInt16 nCount = 0; + sal_uInt16 nCapacity = 0; + if (pRanges) + { + nCount = 1; + while (*pRanges) + { + nCount += 2; + nCapacity += rangeSize(pRanges[0], pRanges[1]); + pRanges += 2; + } + } + return { nCount, nCapacity }; +} + +// Adds a range to which ranges, keeping the ranges in valid state (sorted, non-overlapping) +inline std::unique_ptr<sal_uInt16[]> MergeRange(const sal_uInt16* pWhichRanges, sal_uInt16 nFrom, + sal_uInt16 nTo) +{ + assert(validRange(nFrom, nTo)); + + if (!pWhichRanges) + { + auto pNewRanges = std::make_unique<sal_uInt16[]>(3); + pNewRanges[0] = nFrom; + pNewRanges[1] = nTo; + pNewRanges[2] = 0; + return pNewRanges; + } + + assert(validRanges(pWhichRanges)); + + // create vector of ranges (sal_uInt16 pairs of lower and upper bound) + const size_t nOldCount = CountRanges(pWhichRanges).first; + std::vector<std::pair<sal_uInt16, sal_uInt16>> aRangesTable; + aRangesTable.reserve(nOldCount / 2 + 1); + bool bAdded = false; + for (size_t i = 0; i + 1 < nOldCount; i += 2) + { + if (!bAdded && pWhichRanges[i] >= nFrom) + { // insert new range, keep ranges sorted + aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); + bAdded = true; + } + // insert current range + aRangesTable.emplace_back( + std::pair<sal_uInt16, sal_uInt16>(pWhichRanges[i], pWhichRanges[i + 1])); + } + if (!bAdded) + aRangesTable.emplace_back(std::pair<sal_uInt16, sal_uInt16>(nFrom, nTo)); + + // true if ranges overlap or adjoin, false if ranges are separate + auto needMerge + = [](std::pair<sal_uInt16, sal_uInt16> lhs, std::pair<sal_uInt16, sal_uInt16> rhs) { + return (lhs.first - 1) <= rhs.second && (rhs.first - 1) <= lhs.second; + }; + + auto it = aRangesTable.begin(); + // we got at least one range + for (;;) + { + auto itNext = std::next(it); + if (itNext == aRangesTable.end()) + break; + // check neighbouring ranges, find first range which overlaps or adjoins a previous range + if (needMerge(*it, *itNext)) + { + // lower bounds are sorted, implies: it->first = min(it[0].first, it[1].first) + it->second = std::max(it->second, itNext->second); + aRangesTable.erase(itNext); + } + else + ++it; + } + + // construct range array + const size_t nNewSize = 2 * aRangesTable.size() + 1; + auto pNewRanges = std::make_unique<sal_uInt16[]>(nNewSize); + for (size_t i = 0; i < (nNewSize - 1); i += 2) + std::tie(pNewRanges[i], pNewRanges[i + 1]) = aRangesTable[i / 2]; + + pNewRanges[nNewSize - 1] = 0; + return pNewRanges; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |