557 lines
18 KiB
C++
557 lines
18 KiB
C++
/* -*- 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: */
|