summaryrefslogtreecommitdiffstats
path: root/sc/inc/mtvfunctions.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/inc/mtvfunctions.hxx')
-rw-r--r--sc/inc/mtvfunctions.hxx557
1 files changed, 557 insertions, 0 deletions
diff --git a/sc/inc/mtvfunctions.hxx b/sc/inc/mtvfunctions.hxx
new file mode 100644
index 0000000000..9fe394faff
--- /dev/null
+++ b/sc/inc/mtvfunctions.hxx
@@ -0,0 +1,557 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <mdds/multi_type_vector/types.hpp>
+
+namespace sc {
+
+template<typename SizeT, typename Ret = bool>
+struct FuncElseNoOp
+{
+ Ret operator() (mdds::mtv::element_t, SizeT, SizeT) const
+ {
+ return Ret();
+ }
+};
+
+template<typename FuncElem, typename Elem>
+struct FuncNotElem
+{
+ FuncElem& func;
+ FuncNotElem(FuncElem& f) : func(f) {}
+ bool operator() (size_t s, Elem elem) const
+ {
+ return !func(s, elem);
+ }
+};
+
+/**
+ * Generic algorithm to parse blocks of multi_type_vector either partially
+ * or fully.
+ */
+template<typename StoreT, typename Func>
+typename StoreT::const_iterator
+ParseBlock(
+ const typename StoreT::const_iterator& itPos, const StoreT& rStore, Func& rFunc,
+ typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ rFunc(*it, nOffset, nDataSize);
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+}
+
+/**
+ * Non-const variant of the above function. TODO: Find a way to merge these
+ * two in an elegant way.
+ */
+template<typename StoreT, typename Func>
+typename StoreT::iterator
+ProcessBlock(const typename StoreT::iterator& itPos, StoreT& rStore, Func& rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
+{
+ typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nCurRow = nStart;
+
+ for (; it != rStore.end() && nCurRow <= nEnd; ++it, nOffset = 0, nCurRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nCurRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nCurRow + 1;
+ bLastBlock = true;
+ }
+
+ rFunc(*it, nOffset, nDataSize);
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+}
+
+template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
+void EachElem(NodeT& rNode, size_t nOffset, size_t nDataSize, FuncElem& rFuncElem)
+{
+ ItrT it = BlkT::begin(*rNode.data);
+ std::advance(it, nOffset);
+ ItrT itEnd = it;
+ std::advance(itEnd, nDataSize);
+ size_t nRow = rNode.position + nOffset;
+ for (; it != itEnd; ++it, ++nRow)
+ rFuncElem(nRow, *it);
+}
+
+template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
+void EachElem(NodeT& rNode, FuncElem& rFuncElem)
+{
+ auto it = BlkT::begin(*rNode.data);
+ auto itEnd = BlkT::end(*rNode.data);
+ size_t nRow = rNode.position;
+ for (; it != itEnd; ++it, ++nRow)
+ rFuncElem(nRow, *it);
+}
+
+template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
+void EachElemReverse(NodeT& rNode, FuncElem& rFuncElem)
+{
+ auto it = BlkT::rbegin(*rNode.data);
+ auto itEnd = BlkT::rend(*rNode.data);
+ size_t nRow = rNode.position;
+ for (; it != itEnd; ++it, ++nRow)
+ rFuncElem(nRow, *it);
+}
+
+template<typename BlkT, typename StoreT, typename FuncElem>
+std::pair<typename StoreT::const_iterator, size_t>
+CheckElem(
+ const StoreT& rStore, const typename StoreT::const_iterator& it, size_t nOffset, size_t nDataSize,
+ FuncElem& rFuncElem)
+{
+ typedef std::pair<typename StoreT::const_iterator, size_t> PositionType;
+
+ typename BlkT::const_iterator itData = BlkT::begin(*it->data);
+ std::advance(itData, nOffset);
+ typename BlkT::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ size_t nTopRow = it->position + nOffset;
+ size_t nRow = nTopRow;
+ for (; itData != itDataEnd; ++itData, ++nRow)
+ {
+ if (rFuncElem(nRow, *itData))
+ return PositionType(it, nRow - it->position);
+ }
+
+ return PositionType(rStore.end(), 0);
+}
+
+template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
+void ParseElements1(const StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typename StoreT::size_type nTopRow = 0, nDataSize = 0;
+ typename StoreT::const_iterator it = rStore.begin(), itEnd = rStore.end();
+ for (; it != itEnd; ++it, nTopRow += nDataSize)
+ {
+ nDataSize = it->size;
+ if (it->type != BlkT::block_type)
+ {
+ rFuncElse(it->type, nTopRow, nDataSize);
+ continue;
+ }
+
+ EachElem<BlkT, typename BlkT::const_iterator>(*it, rFuncElem);
+ }
+}
+
+template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
+typename StoreT::const_iterator
+ParseElements1(
+ const typename StoreT::const_iterator& itPos, const StoreT& rStore,
+ typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ if (it->type == BlkT::block_type)
+ EachElem<BlkT, typename BlkT::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ else
+ rFuncElse(it->type, nTopRow, nDataSize);
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+};
+
+template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
+typename StoreT::const_iterator
+ParseElements2(
+ const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ case Blk2::block_type:
+ EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ default:
+ rFuncElse(it->type, nTopRow, nDataSize);
+ }
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+}
+
+template<typename StoreT, typename Blk1, typename Blk2, typename Blk3, typename Blk4, typename FuncElem, typename FuncElse>
+typename StoreT::const_iterator
+ParseElements4(
+ const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ case Blk2::block_type:
+ EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ case Blk3::block_type:
+ EachElem<Blk3, typename Blk3::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ case Blk4::block_type:
+ EachElem<Blk4, typename Blk4::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
+ break;
+ default:
+ rFuncElse(it->type, nTopRow, nDataSize);
+ }
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+}
+
+template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
+void ProcessElements1(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typename StoreT::size_type nTopRow = 0, nDataSize = 0;
+ typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
+ for (; it != itEnd; ++it, nTopRow += nDataSize)
+ {
+ nDataSize = it->size;
+ if (it->type != BlkT::block_type)
+ {
+ rFuncElse(it->type, nTopRow, nDataSize);
+ continue;
+ }
+
+ EachElem<BlkT, typename BlkT::iterator>(*it, rFuncElem);
+ }
+}
+
+/**
+ * This variant specifies start and end positions.
+ */
+template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
+typename StoreT::iterator
+ProcessElements1(
+ const typename StoreT::iterator& itPos, StoreT& rStore,
+ typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType;
+
+ PositionType aPos = rStore.position(itPos, nStart);
+ typename StoreT::iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ if (it->type == BlkT::block_type)
+ EachElem<BlkT, typename BlkT::iterator>(*it, nOffset, nDataSize, rFuncElem);
+ else
+ rFuncElse(it->type, nTopRow, nDataSize);
+
+ if (bLastBlock)
+ break;
+ }
+
+ return it;
+};
+
+template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
+void ProcessElements2(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typename StoreT::size_type nTopRow = 0, nDataSize = 0;
+ typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
+ for (; it != itEnd; ++it, nTopRow += nDataSize)
+ {
+ nDataSize = it->size;
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ EachElem<Blk1, typename Blk1::iterator>(*it, rFuncElem);
+ break;
+ case Blk2::block_type:
+ EachElem<Blk2, typename Blk2::iterator>(*it, rFuncElem);
+ break;
+ default:
+ rFuncElse(it->type, nTopRow, nDataSize);
+ }
+ }
+}
+
+template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
+void ProcessElements2Reverse(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typename StoreT::size_type nTopRow = 0, nDataSize = 0;
+ typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
+ for (; it != itEnd; ++it, nTopRow += nDataSize)
+ {
+ nDataSize = it->size;
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ EachElemReverse<Blk1, typename Blk1::iterator>(*it, rFuncElem);
+ break;
+ case Blk2::block_type:
+ EachElemReverse<Blk2, typename Blk2::iterator>(*it, rFuncElem);
+ break;
+ default:
+ rFuncElse(it->type, nTopRow, nDataSize);
+ }
+ }
+}
+
+template<typename StoreT, typename Blk1, typename FuncElem, typename FuncElse>
+std::pair<typename StoreT::const_iterator, typename StoreT::size_type>
+FindElement1(
+ const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+ typedef std::pair<typename StoreT::size_type, bool> ElseRetType;
+
+ PositionType aPos = rStore.position(nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ {
+ PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem);
+ if (aRet.first != rStore.end())
+ return aRet;
+ }
+ break;
+ default:
+ {
+ ElseRetType aRet = rFuncElse(it->type, nTopRow, nDataSize);
+ if (aRet.second)
+ return PositionType(it, aRet.first);
+ }
+ }
+
+ if (bLastBlock)
+ break;
+ }
+
+ return PositionType(rStore.end(), 0);
+}
+
+template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
+std::pair<typename StoreT::const_iterator, typename StoreT::size_type>
+FindElement2(
+ const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
+ FuncElem& rFuncElem, FuncElse& rFuncElse)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+ typedef std::pair<typename StoreT::size_type, bool> ElseRetType;
+
+ PositionType aPos = rStore.position(nStart);
+ typename StoreT::const_iterator it = aPos.first;
+ typename StoreT::size_type nOffset = aPos.second;
+ typename StoreT::size_type nDataSize = 0;
+ typename StoreT::size_type nTopRow = nStart;
+
+ for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nTopRow + nDataSize - 1 > nEnd)
+ {
+ // Truncate the block.
+ nDataSize = nEnd - nTopRow + 1;
+ bLastBlock = true;
+ }
+
+ switch (it->type)
+ {
+ case Blk1::block_type:
+ {
+ PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem);
+ if (aRet.first != rStore.end())
+ return aRet;
+ }
+ break;
+ case Blk2::block_type:
+ {
+ PositionType aRet = CheckElem<Blk2>(rStore, it, nOffset, nDataSize, rFuncElem);
+ if (aRet.first != rStore.end())
+ return aRet;
+ }
+ break;
+ default:
+ {
+ ElseRetType aRet = rFuncElse(*it, nOffset, nDataSize);
+ if (aRet.second)
+ return PositionType(it, aRet.first);
+ }
+ }
+
+ if (bLastBlock)
+ break;
+ }
+
+ return PositionType(rStore.end(), 0);
+}
+
+// Efficiently set all elements for which the predicate returns true as empty.
+template<typename Blk1, typename StoreT, typename FuncElem>
+void SetElementsToEmpty1(
+ StoreT& rStore, FuncElem& rFuncElem)
+{
+ typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
+
+ for (typename StoreT::iterator it = rStore.begin(); it != rStore.end(); ++it)
+ {
+ if (it->type == Blk1::block_type)
+ {
+ PositionType firstToEmpty = CheckElem<Blk1>(rStore, it, 0, it->size, rFuncElem);
+ if (firstToEmpty.first != rStore.end())
+ {
+ typename StoreT::size_type nFirstOffset = firstToEmpty.second;
+ typename StoreT::size_type nRemainingDataSize = it->size - nFirstOffset;
+ FuncNotElem<FuncElem, typename Blk1::value_type> notFuncElem(rFuncElem);
+ PositionType lastToEmpty = CheckElem<Blk1>(rStore, it, nFirstOffset, nRemainingDataSize,
+ notFuncElem);
+ typename StoreT::size_type nLastOffset = lastToEmpty.first != rStore.end()
+ ? lastToEmpty.second - 1 : it->size - 1;
+ it = rStore.set_empty(it, it->position + nFirstOffset, it->position + nLastOffset);
+ // The returned iterator points to the empty elements block.
+ assert(it->type == sc::element_type_empty);
+ }
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */