tdf#135683 speedup DocumentRedlineManager::GetRedlinePos
use binary search
Change-Id: Icd442ba18cb27cdcb5955fa8bbce421b26d5ad44
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121205
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx
index 6463534..08e2d8b 100644
--- a/sw/inc/docary.hxx
+++ b/sw/inc/docary.hxx
@@ -224,6 +224,9 @@
static constexpr size_type npos = SAL_MAX_INT32;
private:
vector_type maVector;
/// Sometimes we load bad data, and we need to know if we can use
/// fast binary search, or if we have to fall back to a linear search
bool m_bHasOverlappingElements;
public:
~SwRedlineTable();
bool Contains(const SwRangeRedline* p) const { return maVector.find(const_cast<SwRangeRedline*>(p)) != maVector.end(); }
@@ -232,6 +235,7 @@
bool Insert(SwRangeRedline*& p);
bool Insert(SwRangeRedline*& p, size_type& rInsPos);
bool InsertWithValidRanges(SwRangeRedline*& p, size_type* pInsPos = nullptr);
bool HasOverlappingElements() const { return m_bHasOverlappingElements; }
void Remove( size_type nPos );
void Remove( const SwRangeRedline* p );
@@ -266,6 +270,9 @@
// Notifies all LOK clients when redlines are added/modified/removed
static void LOKRedlineNotification(RedlineNotification eType, SwRangeRedline* pRedline);
private:
void CheckOverlapping(vector_type::const_iterator it);
};
/// Table that holds 'extra' redlines, such as 'table row insert/delete', 'paragraph moves' etc...
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index f7b39e9..af2965f 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -76,7 +76,7 @@
// check validity of the redline table. Checks redline bounds, and make
// sure the redlines are sorted and non-overlapping.
void lcl_CheckRedline( IDocumentRedlineAccess& redlineAccess )
void lcl_CheckRedline( const IDocumentRedlineAccess& redlineAccess )
{
const SwRedlineTable& rTable = redlineAccess.GetRedlineTable();
@@ -2620,19 +2620,45 @@
SwRedlineTable::size_type DocumentRedlineManager::GetRedlinePos( const SwNode& rNd, RedlineType nType ) const
{
const sal_uLong nNdIdx = rNd.GetIndex();
for( SwRedlineTable::size_type n = 0; n < maRedlineTable.size() ; ++n )
// if the table only contains good (i.e. non-overlapping) data, we can do a binary search
if (!maRedlineTable.HasOverlappingElements())
{
const SwRangeRedline* pTmp = maRedlineTable[ n ];
sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
nMk = pTmp->GetMark()->nNode.GetIndex();
if( nPt < nMk ) { tools::Long nTmp = nMk; nMk = nPt; nPt = nTmp; }
// binary search to the first redline with end >= the needle
auto it = std::lower_bound(maRedlineTable.begin(), maRedlineTable.end(), rNd,
[&nNdIdx](const SwRangeRedline* lhs, const SwNode& /*rhs*/)
{
return lhs->End()->nNode.GetIndex() < nNdIdx;
});
for( ; it != maRedlineTable.end(); ++it)
{
const SwRangeRedline* pTmp = *it;
sal_uLong nStart = pTmp->Start()->nNode.GetIndex(),
nEnd = pTmp->End()->nNode.GetIndex();
if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
nMk <= nNdIdx && nNdIdx <= nPt )
return n;
if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
nStart <= nNdIdx && nNdIdx <= nEnd )
return std::distance(maRedlineTable.begin(), it);
if( nMk > nNdIdx )
break;
if( nStart > nNdIdx )
break;
}
}
else
{
for( SwRedlineTable::size_type n = 0; n < maRedlineTable.size() ; ++n )
{
const SwRangeRedline* pTmp = maRedlineTable[ n ];
sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
nMk = pTmp->GetMark()->nNode.GetIndex();
if( nPt < nMk ) { tools::Long nTmp = nMk; nMk = nPt; nPt = nTmp; }
if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
nMk <= nNdIdx && nNdIdx <= nPt )
return n;
if( nMk > nNdIdx )
break;
}
}
return SwRedlineTable::npos;
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 27fbb81..5e1cae4 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -436,11 +436,38 @@
size_type nP = rv.first - begin();
LOKRedlineNotification(RedlineNotification::Add, p);
p->CallDisplayFunc(nP);
if (rv.second)
CheckOverlapping(rv.first);
return rv.second;
}
return InsertWithValidRanges( p );
}
void SwRedlineTable::CheckOverlapping(vector_type::const_iterator it)
{
if (m_bHasOverlappingElements)
return;
if (maVector.size() <= 1) // a single element cannot be overlapping
return;
auto pCurr = *it;
auto itNext = it + 1;
if (itNext != maVector.end())
{
auto pNext = *itNext;
if (pCurr->End()->nNode.GetIndex() >= pNext->Start()->nNode.GetIndex())
{
m_bHasOverlappingElements = true;
return;
}
}
if (it != maVector.begin())
{
auto pPrev = *(it - 1);
if (pPrev->End()->nNode.GetIndex() >= pCurr->Start()->nNode.GetIndex())
m_bHasOverlappingElements = true;
}
}
bool SwRedlineTable::Insert(SwRangeRedline*& p, size_type& rP)
{
if( p->HasValidRange() )
@@ -448,6 +475,8 @@
std::pair<vector_type::const_iterator, bool> rv = maVector.insert( p );
rP = rv.first - begin();
p->CallDisplayFunc(rP);
if (rv.second)
CheckOverlapping(rv.first);
return rv.second;
}
return InsertWithValidRanges( p, &rP );
@@ -640,6 +669,7 @@
LOKRedlineNotification(RedlineNotification::Remove, pRedline);
delete pRedline;
}
m_bHasOverlappingElements = false;
}
void SwRedlineTable::DeleteAndDestroy(size_type const nP)