LibreOffice Module sc (master) 1
bcaslot.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sfx2/objsh.hxx>
21#include <svl/listener.hxx>
22#include <sal/log.hxx>
23#include <osl/diagnose.h>
24
25#include <document.hxx>
26#include <brdcst.hxx>
27#include <bcaslot.hxx>
28#include <scerrors.hxx>
29#include <refupdat.hxx>
30#include <bulkdatahint.hxx>
31#include <columnspanset.hxx>
32#include <formulacell.hxx>
33#include <grouparealistener.hxx>
34#include <broadcast.hxx>
35
37 pUpdateChainNext(nullptr),
38 aRange(rRange),
39 nRefCount(0),
40 mbInUpdateChain(false),
41 mbGroupListening(false) {}
42
45 aTmpSeekBroadcastArea( ScRange()),
46 pDoc( pDocument ),
47 pBASM( pBASMa ),
48 mbInBroadcastIteration( false),
49 mbHasErasedArea(false)
50{
51}
52
54{
55 for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
56 aIter != aBroadcastAreaTbl.end(); /* none */)
57 {
58 // Prevent hash from accessing dangling pointer in case area is
59 // deleted.
60 ScBroadcastArea* pArea = (*aIter).mpArea;
61 // Erase all so no hash will be accessed upon destruction of the
62 // unordered_map.
63 aIter = aBroadcastAreaTbl.erase(aIter);
64 if (!pArea->DecRef())
65 delete pArea;
66 }
67}
68
70{
73 {
74 if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
75 { // this is more hypothetical now, check existed for old SV_PTRARR_SORT
77 OSL_ENSURE( pShell, "Missing DocShell :-/" );
78
79 if ( pShell )
81
82 pDoc->SetAutoCalc( false );
84 pDoc->SetHardRecalcState( eState );
85 }
86 }
87 return eState;
88}
89
91 const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea )
92{
93 bool bNewArea = false;
94 OSL_ENSURE(pListener, "StartListeningArea: pListener Null");
95 assert(!pDoc->IsDelayedFormulaGrouping()); // otherwise the group size might be incorrect
97 return false;
98 if ( !rpArea )
99 {
100 // Even if most times the area doesn't exist yet and immediately trying
101 // to new and insert it would save an attempt to find it, on massive
102 // operations like identical large [HV]LOOKUP() areas the new/delete
103 // would add quite some penalty for all but the first formula cell.
104 ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange, bGroupListening));
105 if (aIter != aBroadcastAreaTbl.end())
106 rpArea = (*aIter).mpArea;
107 else
108 {
109 rpArea = new ScBroadcastArea( rRange);
110 rpArea->SetGroupListening(bGroupListening);
111 if (aBroadcastAreaTbl.insert( rpArea).second)
112 {
113 rpArea->IncRef();
114 bNewArea = true;
115 }
116 else
117 {
118 OSL_FAIL("StartListeningArea: area not found and not inserted in slot?!?");
119 delete rpArea;
120 rpArea = nullptr;
121 }
122 }
123 if (rpArea)
124 pListener->StartListening( rpArea->GetBroadcaster());
125 }
126 else
127 {
128 if (aBroadcastAreaTbl.insert( rpArea).second)
129 rpArea->IncRef();
130 }
131 return bNewArea;
132}
133
135{
136 OSL_ENSURE( pArea, "InsertListeningArea: pArea NULL");
138 return;
139 if (aBroadcastAreaTbl.insert( pArea).second)
140 pArea->IncRef();
141}
142
143// If rpArea != NULL then no listeners are stopped, only the area is removed
144// and the reference count decremented.
146 const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea )
147{
148 OSL_ENSURE(pListener, "EndListeningArea: pListener Null");
149 if ( !rpArea )
150 {
151 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange, bGroupListening));
152 if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
153 return;
154 rpArea = (*aIter).mpArea;
155 pListener->EndListening( rpArea->GetBroadcaster() );
156 if ( !rpArea->GetBroadcaster().HasListeners() )
157 { // if nobody is listening we can dispose it
158 if (rpArea->GetRef() == 1)
159 rpArea = nullptr; // will be deleted by erase
160 EraseArea( aIter);
161 }
162 }
163 else
164 {
165 if (rpArea && !rpArea->GetBroadcaster().HasListeners())
166 {
167 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange, bGroupListening));
168 if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
169 return;
170 OSL_ENSURE( (*aIter).mpArea == rpArea, "EndListeningArea: area pointer mismatch");
171 if (rpArea->GetRef() == 1)
172 rpArea = nullptr; // will be deleted by erase
173 EraseArea( aIter);
174 }
175 }
176}
177
178ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
179 const ScRange& rRange, bool bGroupListening )
180{
184}
185
186namespace {
187
188void broadcastRangeByCell( SvtBroadcaster& rBC, const ScRange& rRange, SfxHintId nHint )
189{
190 ScHint aHint(nHint, ScAddress());
191 for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
192 {
193 aHint.SetAddressTab(nTab);
194 for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
195 {
196 aHint.SetAddressCol(nCol);
197 for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
198 {
199 aHint.SetAddressRow(nRow);
200 rBC.Broadcast(aHint);
201 }
202 }
203 }
204}
205
206}
207
209{
210 if (aBroadcastAreaTbl.empty())
211 return false;
212
213 bool bInBroadcast = mbInBroadcastIteration;
215 bool bIsBroadcasted = false;
216
217 mbHasErasedArea = false;
218
219 for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
220 aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
221 {
222 if (mbHasErasedArea && isMarkedErased( aIter))
223 continue;
224
225 ScBroadcastArea* pArea = (*aIter).mpArea;
226 const ScRange& rAreaRange = pArea->GetRange();
227
228 // Take the intersection of the area range and the broadcast range.
229 ScRange aIntersection = rAreaRange.Intersection(rRange);
230 if (!aIntersection.IsValid())
231 continue;
232
233 if (pArea->IsGroupListening())
234 {
236 {
237 pBASM->InsertBulkGroupArea(pArea, aIntersection);
238 }
239 else
240 {
241 broadcastRangeByCell(pArea->GetBroadcaster(), aIntersection, nHint);
242 bIsBroadcasted = true;
243 }
244 }
245 else if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
246 {
247 broadcastRangeByCell(pArea->GetBroadcaster(), aIntersection, nHint);
248 bIsBroadcasted = true;
249 }
250 }
251
252 mbInBroadcastIteration = bInBroadcast;
253
254 // A Notify() during broadcast may call EndListeningArea() and thus dispose
255 // an area if it was the last listener, which would invalidate an iterator
256 // pointing to it, hence the real erase is done afterwards.
258
259 return bIsBroadcasted;
260}
261
263{
264 if (aBroadcastAreaTbl.empty())
265 return false;
266
267 bool bInBroadcast = mbInBroadcastIteration;
269 bool bIsBroadcasted = false;
270
271 mbHasErasedArea = false;
272
273 const ScRange& rRange = rHint.GetRange();
274 for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
275 aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
276 {
277 if (mbHasErasedArea && isMarkedErased( aIter))
278 continue;
279
280 ScBroadcastArea* pArea = (*aIter).mpArea;
281 const ScRange& rAreaRange = pArea->GetRange();
282 if (rAreaRange.Intersects( rRange))
283 {
284 if (pArea->IsGroupListening())
285 {
287 {
288 pBASM->InsertBulkGroupArea(pArea, rRange);
289 }
290 else
291 {
292 pArea->GetBroadcaster().Broadcast( rHint);
293 bIsBroadcasted = true;
294 }
295 }
296 else if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
297 {
298 pArea->GetBroadcaster().Broadcast( rHint);
299 bIsBroadcasted = true;
300 }
301 }
302 }
303
304 mbInBroadcastIteration = bInBroadcast;
305
306 // A Notify() during broadcast may call EndListeningArea() and thus dispose
307 // an area if it was the last listener, which would invalidate an iterator
308 // pointing to it, hence the real erase is done afterwards.
310
311 return bIsBroadcasted;
312}
313
315{
316 if (aBroadcastAreaTbl.empty())
317 return;
318 for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
319 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
320 {
321 const ScRange& rAreaRange = (*aIter).mpArea->GetRange();
322 if (rRange.Contains( rAreaRange))
323 {
324 ScBroadcastArea* pArea = (*aIter).mpArea;
325 aIter = aBroadcastAreaTbl.erase(aIter); // erase before modifying
326 if (!pArea->DecRef())
327 {
329 pBASM->RemoveBulkArea( pArea);
330 delete pArea;
331 }
332 }
333 else
334 ++aIter;
335 }
336}
337
339 const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz )
340{
341 if (aBroadcastAreaTbl.empty())
342 return;
343
344 SCCOL nCol1, nCol2, theCol1, theCol2;
345 SCROW nRow1, nRow2, theRow1, theRow2;
346 SCTAB nTab1, nTab2, theTab1, theTab2;
347 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
348 for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
349 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
350 {
351 ScBroadcastArea* pArea = (*aIter).mpArea;
352 if ( pArea->IsInUpdateChain() )
353 {
354 aIter = aBroadcastAreaTbl.erase(aIter);
355 pArea->DecRef();
356 }
357 else
358 {
359 pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
360 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
361 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
362 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
363 {
364 aIter = aBroadcastAreaTbl.erase(aIter);
365 pArea->DecRef();
367 pBASM->RemoveBulkArea( pArea);
368 pArea->SetInUpdateChain( true );
370 if ( pUC )
371 pUC->SetUpdateChainNext( pArea );
372 else // no tail => no head
373 pBASM->SetUpdateChain( pArea );
374 pBASM->SetEOUpdateChain( pArea );
375 }
376 else
377 ++aIter;
378 }
379 }
380}
381
383{
384 ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
385 if (aIter == aBroadcastAreaTbl.end())
386 return;
387 if ((*aIter).mpArea != pArea)
388 OSL_FAIL( "UpdateRemoveArea: area pointer mismatch");
389 else
390 {
391 aBroadcastAreaTbl.erase( aIter);
392 pArea->DecRef();
393 }
394}
395
397{
398 ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
399 aBroadcastAreaTbl.insert( pArea);
400 if (aPair.second)
401 pArea->IncRef();
402 else
403 {
404 // Identical area already exists, add listeners.
405 ScBroadcastArea* pTarget = (*(aPair.first)).mpArea;
406 if (pArea != pTarget)
407 {
410 for (auto& pListener : rListeners)
411 {
412 SvtListener& rListener = *pListener;
413 rListener.StartListening(rTarget);
414 }
415 }
416 }
417}
418
419void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
420{
422 {
423 (*rIter).mbErasure = true; // mark for erasure
424 mbHasErasedArea = true; // at least one area is marked for erasure.
425 pBASM->PushAreaToBeErased( this, rIter);
426 }
427 else
428 {
429 ScBroadcastArea* pArea = (*rIter).mpArea;
430 aBroadcastAreaTbl.erase( rIter);
431 if (!pArea->DecRef())
432 {
435 delete pArea;
436 }
437 }
438}
439
441 const ScRange& rRange, std::vector<sc::AreaListener>& rListeners,
443{
444 for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
445 aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
446 {
447 if (isMarkedErased( aIter))
448 continue;
449
450 ScBroadcastArea* pArea = (*aIter).mpArea;
451 const ScRange& rAreaRange = pArea->GetRange();
452 switch (eGroup)
453 {
455 if (!pArea->IsGroupListening())
456 continue;
457 break;
459 default:
460 ;
461 }
462
463 switch (eType)
464 {
466 if (!rRange.Contains(rAreaRange))
467 // The range needs to be fully inside specified range.
468 continue;
469 break;
471 if (!rRange.Intersects(rAreaRange))
472 // The range needs to be partially overlapping or fully inside.
473 continue;
474 break;
476 if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.Contains(rAreaRange))
477 // The range needs to be one single row and fully inside
478 // specified range.
479 continue;
480 break;
482 if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.Contains(rAreaRange))
483 // The range needs to be one single column and fully inside
484 // specified range.
485 continue;
486 break;
487 }
488
490 for (const auto& pListener : rLst)
491 {
492 sc::AreaListener aEntry;
493 aEntry.maArea = rAreaRange;
494 aEntry.mbGroupListening = pArea->IsGroupListening();
495 aEntry.mpListener = pListener;
496 rListeners.push_back(aEntry);
497 }
498 }
499}
500
502{
503 for (const ScBroadcastAreaEntry& rEntry : aBroadcastAreaTbl)
504 {
505 const ScRange& rRange = rEntry.mpArea->GetRange();
506 auto aRes = rState.aAreaListenerStore.try_emplace(rRange);
507 auto& rLisStore = aRes.first->second;
508
509 for (const SvtListener* pLis : rEntry.mpArea->GetBroadcaster().GetAllListeners())
510 {
511 if (auto pFC = dynamic_cast<const ScFormulaCell*>(pLis); pFC)
512 {
513 rLisStore.emplace_back(pFC);
514 continue;
515 }
516
517 if (auto pFGL = dynamic_cast<const sc::FormulaGroupAreaListener*>(pLis); pFGL)
518 {
519 rLisStore.emplace_back(pFGL);
520 continue;
521 }
522
523 rLisStore.emplace_back(pLis);
524 }
525 }
526}
527
529{
530 pBASM->FinallyEraseAreas( this);
531}
532
533// --- ScBroadcastAreaSlotMachine -------------------------------------
534
536 : mnBcaSlots(nBcaSlots)
537{
538 ppSlots.reset( new ScBroadcastAreaSlot* [ nBcaSlots ] );
539 memset( ppSlots.get(), 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
540}
541
543 : mnBcaSlots(rOther.mnBcaSlots)
544 , ppSlots( std::move(rOther.ppSlots) )
545{
546}
547
549{
550 if (ppSlots)
551 for ( ScBroadcastAreaSlot** pp = ppSlots.get() + mnBcaSlots; --pp >= ppSlots.get(); /* nothing */ )
552 delete *pp;
553}
554
556 ScDocument* pDocument ) :
557 pDoc( pDocument ),
558 pUpdateChain( nullptr ),
559 pEOUpdateChain( nullptr ),
561{
562 // initSlotDistribution ---------
563 // Logarithmic or any other distribution.
564 // Upper and leftmost sheet part usually is more populated and referenced and gets fine
565 // grained resolution, larger data in larger hunks.
566 // Just like with cells, slots are organized in columns. Slot 0 is for first nSliceRow x nSliceCol
567 // cells, slot 1 is for next nSliceRow x nSliceCel cells below, etc. After a while the size of row
568 // slice doubles (making more cells share the same slot), this distribution data is stored
569 // in ScSlotData including ranges of cells. This is repeated for another column of nSliceCol cells,
570 // again with the column slice doubling after some time.
571 // Functions ComputeSlotOffset(), ComputeArePoints() and ComputeNextSlot() do the necessary
572 // calculations.
573 SCSIZE nSlots = 0;
574 // This should be SCCOL, but that's only 16bit and would overflow when doubling 16k columns.
575 sal_Int32 nCol1 = 0;
576 sal_Int32 nCol2 = 1024;
577 SCSIZE nSliceCol = 16;
578 while (nCol2 <= pDoc->GetMaxColCount())
579 {
580 SCROW nRow1 = 0;
581 SCROW nRow2 = 32*1024;
582 SCSIZE nSliceRow = 128;
583 SCSIZE nSlotsCol = 0;
584 SCSIZE nSlotsStartCol = nSlots;
585 // Must be sorted by row1,row2!
586 while (nRow2 <= pDoc->GetMaxRowCount())
587 {
588 maSlotDistribution.emplace_back(nRow1, nRow2, nSliceRow, nSlotsCol, nCol1, nCol2, nSliceCol, nSlotsStartCol);
589 nSlotsCol += (nRow2 - nRow1) / nSliceRow;
590 nRow1 = nRow2;
591 nRow2 *= 2;
592 nSliceRow *= 2;
593 }
594 // Store the number of slots in a column in mnBcaSlotsCol, so that finding a slot
595 // to the right can be computed quickly in ComputeNextSlot().
596 if(nCol1 == 0)
597 mnBcaSlotsCol = nSlotsCol;
598 assert(nSlotsCol == mnBcaSlotsCol);
599 nSlots += (nCol2 - nCol1) / nSliceCol * nSlotsCol;
600 nCol1 = nCol2;
601 nCol2 *= 2;
602 nSliceCol *= 2;
603 }
604 mnBcaSlots = nSlots;
605#ifdef DBG_UTIL
606 DoChecks();
607#endif
608}
609
611{
612 aTableSlotsMap.clear();
613 pBCAlways.reset();
614 // Areas to-be-erased still present is a serious error in handling, but at
615 // this stage there's nothing we can do anymore.
616 SAL_WARN_IF( !maAreasToBeErased.empty(), "sc.core", "ScBroadcastAreaSlotMachine::dtor: maAreasToBeErased not empty");
617}
618
620 const ScAddress& rAddress ) const
621{
622 SCROW nRow = rAddress.Row();
623 SCCOL nCol = rAddress.Col();
624 if ( !pDoc->ValidRow(nRow) || !pDoc->ValidCol(nCol) )
625 {
626 OSL_FAIL( "Row/Col invalid, using first slot!" );
627 return 0;
628 }
629 for (const ScSlotData& rSD : maSlotDistribution)
630 {
631 if (nRow < rSD.nStopRow && nCol < rSD.nStopCol)
632 {
633 assert(nRow >= rSD.nStartRow);
634 assert(nCol >= rSD.nStartCol);
635 SCSIZE slot = rSD.nCumulatedRow
636 + static_cast<SCSIZE>(nRow - rSD.nStartRow) / rSD.nSliceRow
637 + rSD.nCumulatedCol
638 + static_cast<SCSIZE>(nCol - rSD.nStartCol) / rSD.nSliceCol * mnBcaSlotsCol;
639 assert(slot < mnBcaSlots);
640 return slot;
641 }
642 }
643 OSL_FAIL( "No slot found, using last!" );
644 return mnBcaSlots - 1;
645}
646
648 SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
649{
650 rStart = ComputeSlotOffset( rRange.aStart );
651 rEnd = ComputeSlotOffset( rRange.aEnd );
652 // count of row slots per column minus one
653 rRowBreak = ComputeSlotOffset(
654 ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
655}
656
657static void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
658 SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE nRowBreak, SCSIZE nBcaSlotsCol )
659{
660 if ( nOff < nBreak )
661 {
662 ++nOff;
663 ++pp;
664 }
665 else
666 {
667 nStart += nBcaSlotsCol;
668 nOff = nStart;
669 pp = ppSlots + nOff;
670 nBreak = nOff + nRowBreak;
671 }
672}
673
674#ifdef DBG_UTIL
675static void compare(SCSIZE value1, SCSIZE value2, int line)
676{
677 if(value1!=value2)
678 SAL_WARN("sc", "V1:" << value1 << " V2:" << value2 << " (" << line << ")");
679 assert(value1 == value2);
680}
681
682// Basic checks that the calculations work correctly.
684{
685 // Copy&paste from the ctor.
686 constexpr SCSIZE nSliceRow = 128;
687 constexpr SCSIZE nSliceCol = 16;
688 // First and second column are in the same slice and so get the same slot.
689 compare( ComputeSlotOffset( ScAddress( 0, 0, 0 )), ComputeSlotOffset( ScAddress( 1, 0, 0 )), __LINE__);
690 // Each nSliceRow rows are offset by one slot (at the start of the logarithmic distribution).
691 compare( ComputeSlotOffset( ScAddress( 0, 0, 0 )),
692 ComputeSlotOffset( ScAddress( 0, nSliceRow, 0 )) - 1, __LINE__ );
693 compare( ComputeSlotOffset( ScAddress( nSliceCol - 1, 0, 0 )),
694 ComputeSlotOffset( ScAddress( nSliceCol, 0, 0 )) - mnBcaSlotsCol, __LINE__ );
695 // Check that last cell is the last slot.
697 mnBcaSlots - 1, __LINE__ );
698 // Check that adjacent rows in the same column but in different distribution areas differ by one slot.
699 for( size_t i = 0; i < maSlotDistribution.size() - 1; ++i )
700 {
701 const ScSlotData& s1 = maSlotDistribution[ i ];
702 const ScSlotData& s2 = maSlotDistribution[ i + 1 ];
703 if( s1.nStartCol == s2.nStartCol )
704 {
705 assert( s1.nStopRow == s2.nStartRow );
707 ComputeSlotOffset( ScAddress( s1.nStartCol, s1.nStopRow, 0 )) - 1, __LINE__ );
708 }
709 }
710 // Check that adjacent columns in the same row but in different distribution areas differ by mnBcaSlotsCol.
711 for( size_t i = 0; i < maSlotDistribution.size() - 1; ++i )
712 {
713 const ScSlotData& s1 = maSlotDistribution[ i ];
714 for( size_t j = i + 1; j < maSlotDistribution.size(); ++j )
715 {
716 const ScSlotData& s2 = maSlotDistribution[ i + 1 ];
717 if( s1.nStartRow == s2.nStartRow && s1.nStopCol == s2.nStartCol )
718 {
719 assert( s1.nStopRow == s2.nStartRow );
721 ComputeSlotOffset( ScAddress( s1.nStopCol, s1.nStartRow, 0 )) - mnBcaSlotsCol, __LINE__ );
722 }
723 }
724 }
725 // Iterate all slots.
726 ScRange range( ScAddress( 0, 0, 0 ), ScAddress( pDoc->MaxCol(), pDoc->MaxRow(), 0 ));
727 SCSIZE nStart, nEnd, nRowBreak;
728 ComputeAreaPoints( range, nStart, nEnd, nRowBreak );
729 assert( nStart == 0 );
730 assert( nEnd == mnBcaSlots - 1 );
731 SCSIZE nOff = nStart;
732 SCSIZE nBreak = nOff + nRowBreak;
733 std::unique_ptr<ScBroadcastAreaSlot*[]> slots( new ScBroadcastAreaSlot*[ mnBcaSlots ] ); // dummy, not accessed
734 ScBroadcastAreaSlot** ppSlots = slots.get();
735 ScBroadcastAreaSlot** pp = ppSlots;
736 while ( nOff <= nEnd )
737 {
738 SCSIZE previous = nOff;
739 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
740 compare( nOff, previous + 1, __LINE__ );
741 }
742 // Iterate slots in the last row (each will differ by mnBcaSlotsCol).
743 range = ScRange( ScAddress( 0, pDoc->MaxRow(), 0 ),
744 ScAddress( pDoc->MaxCol(), pDoc->MaxRow() - 1, 0 ));
745 ComputeAreaPoints( range, nStart, nEnd, nRowBreak );
746 assert( nStart == mnBcaSlotsCol - 1 );
747 assert( nEnd == mnBcaSlots - 1 );
748 nOff = nStart;
749 nBreak = nOff + nRowBreak;
750 ppSlots = slots.get();
751 pp = ppSlots;
752 while ( nOff <= nEnd )
753 {
754 SCSIZE previous = nOff;
755 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
756 compare( nOff, previous + mnBcaSlotsCol, __LINE__ );
757 }
758}
759#endif
760
762 const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
763{
764 if ( rRange == BCA_LISTEN_ALWAYS )
765 {
766 if ( !pBCAlways )
767 pBCAlways.reset( new SvtBroadcaster );
768 pListener->StartListening( *pBCAlways );
769 }
770 else
771 {
772 // A new area needs to be inserted to the corresponding slots, for 3D
773 // ranges for all sheets, do not slice into per sheet areas or the
774 // !bDone will break too early (i.e. after the first sheet) if
775 // subsequent listeners are to be added.
776 ScBroadcastArea* pArea = nullptr;
777 bool bDone = false;
778 for (SCTAB nTab = rRange.aStart.Tab();
779 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
780 {
781 TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
782 if (iTab == aTableSlotsMap.end())
783 iTab = aTableSlotsMap.emplace( std::piecewise_construct,
784 std::forward_as_tuple(nTab), std::forward_as_tuple(mnBcaSlots) ).first;
785 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
786 SCSIZE nStart, nEnd, nRowBreak;
787 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
788 SCSIZE nOff = nStart;
789 SCSIZE nBreak = nOff + nRowBreak;
790 ScBroadcastAreaSlot** pp = ppSlots + nOff;
791 while ( !bDone && nOff <= nEnd )
792 {
793 if ( !*pp )
794 *pp = new ScBroadcastAreaSlot( pDoc, this );
795 if (!pArea)
796 {
797 // If the call to StartListeningArea didn't create the
798 // ScBroadcastArea, listeners were added to an already
799 // existing identical area that doesn't need to be inserted
800 // to slots again.
801 if (!(*pp)->StartListeningArea( rRange, bGroupListening, pListener, pArea))
802 bDone = true;
803 }
804 else
805 (*pp)->InsertListeningArea( pArea);
806 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
807 }
808 }
809 }
810}
811
813 const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
814{
815 if ( rRange == BCA_LISTEN_ALWAYS )
816 {
817 if ( pBCAlways )
818 {
819 pListener->EndListening( *pBCAlways);
820 if (!pBCAlways->HasListeners())
821 {
822 pBCAlways.reset();
823 }
824 }
825 }
826 else
827 {
828 SCTAB nEndTab = rRange.aEnd.Tab();
829 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
830 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
831 {
832 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
833 SCSIZE nStart, nEnd, nRowBreak;
834 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
835 SCSIZE nOff = nStart;
836 SCSIZE nBreak = nOff + nRowBreak;
837 ScBroadcastAreaSlot** pp = ppSlots + nOff;
838 ScBroadcastArea* pArea = nullptr;
839 if (nOff == 0 && nEnd == mnBcaSlots-1)
840 {
841 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
842 // happen for insertion and deletion of sheets.
843 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
844 do
845 {
846 if ( *pp )
847 (*pp)->EndListeningArea( rRange, bGroupListening, pListener, pArea);
848 } while (++pp < pStop);
849 }
850 else
851 {
852 while ( nOff <= nEnd )
853 {
854 if ( *pp )
855 (*pp)->EndListeningArea( rRange, bGroupListening, pListener, pArea);
856 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
857 }
858 }
859 }
860 }
861}
862
864{
865 bool bBroadcasted = false;
866 SCTAB nEndTab = rRange.aEnd.Tab();
867 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
868 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
869 {
870 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
871 SCSIZE nStart, nEnd, nRowBreak;
872 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
873 SCSIZE nOff = nStart;
874 SCSIZE nBreak = nOff + nRowBreak;
875 ScBroadcastAreaSlot** pp = ppSlots + nOff;
876 while ( nOff <= nEnd )
877 {
878 if ( *pp )
879 bBroadcasted |= (*pp)->AreaBroadcast( rRange, nHint );
880 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
881 }
882 }
883 return bBroadcasted;
884}
885
887{
888 const ScAddress& rAddress = rHint.GetStartAddress();
889 if ( rAddress == BCA_BRDCST_ALWAYS )
890 {
891 if ( pBCAlways )
892 {
893 pBCAlways->Broadcast( rHint );
894 return true;
895 }
896 else
897 return false;
898 }
899 else
900 {
901 TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
902 if (iTab == aTableSlotsMap.end())
903 return false;
904 // Process all slots for the given row range.
905 ScRange broadcastRange( rAddress,
906 ScAddress( rAddress.Col(), rAddress.Row() + rHint.GetRowCount() - 1, rAddress.Tab()));
907 bool bBroadcasted = false;
908 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
909 SCSIZE nStart, nEnd, nRowBreak;
910 ComputeAreaPoints( broadcastRange, nStart, nEnd, nRowBreak );
911 SCSIZE nOff = nStart;
912 SCSIZE nBreak = nOff + nRowBreak;
913 ScBroadcastAreaSlot** pp = ppSlots + nOff;
914 while ( nOff <= nEnd )
915 {
916 if ( *pp )
917 bBroadcasted |= (*pp)->AreaBroadcast( rHint );
918 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
919 }
920 return bBroadcasted;
921 }
922}
923
925 const ScRange& rRange )
926{
927 SCTAB nEndTab = rRange.aEnd.Tab();
928 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
929 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
930 {
931 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
932 SCSIZE nStart, nEnd, nRowBreak;
933 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
934 SCSIZE nOff = nStart;
935 SCSIZE nBreak = nOff + nRowBreak;
936 ScBroadcastAreaSlot** pp = ppSlots + nOff;
937 if (nOff == 0 && nEnd == mnBcaSlots-1)
938 {
939 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
940 // happen for insertion and deletion of sheets.
941 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
942 do
943 {
944 if ( *pp )
945 (*pp)->DelBroadcastAreasInRange( rRange );
946 } while (++pp < pStop);
947 }
948 else
949 {
950 while ( nOff <= nEnd )
951 {
952 if ( *pp )
953 (*pp)->DelBroadcastAreasInRange( rRange );
954 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
955 }
956 }
957 }
958}
959
960// for all affected: remove, chain, update range, insert, and maybe delete
962 UpdateRefMode eUpdateRefMode,
963 const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz )
964{
965 // remove affected and put in chain
966 SCTAB nEndTab = rRange.aEnd.Tab();
967 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
968 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
969 {
970 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
971 SCSIZE nStart, nEnd, nRowBreak;
972 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
973 SCSIZE nOff = nStart;
974 SCSIZE nBreak = nOff + nRowBreak;
975 ScBroadcastAreaSlot** pp = ppSlots + nOff;
976 if (nOff == 0 && nEnd == mnBcaSlots-1)
977 {
978 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
979 // happen for insertion and deletion of sheets.
980 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
981 do
982 {
983 if ( *pp )
984 (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
985 } while (++pp < pStop);
986 }
987 else
988 {
989 while ( nOff <= nEnd )
990 {
991 if ( *pp )
992 (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
993 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
994 }
995 }
996 }
997
998 // Updating an area's range will modify the hash key, remove areas from all
999 // affected slots. Will be reinserted later with the updated range.
1000 ScBroadcastArea* pChain = pUpdateChain;
1001 while (pChain)
1002 {
1003 ScBroadcastArea* pArea = pChain;
1004 pChain = pArea->GetUpdateChainNext();
1005 ScRange aRange( pArea->GetRange());
1006 // remove from slots
1007 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
1008 {
1009 TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
1010 if (iTab == aTableSlotsMap.end())
1011 {
1012 OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
1013 continue; // for
1014 }
1015 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
1016 SCSIZE nStart, nEnd, nRowBreak;
1017 ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
1018 SCSIZE nOff = nStart;
1019 SCSIZE nBreak = nOff + nRowBreak;
1020 ScBroadcastAreaSlot** pp = ppSlots + nOff;
1021 while ( nOff <= nEnd && pArea->GetRef() )
1022 {
1023 if (*pp)
1024 (*pp)->UpdateRemoveArea( pArea);
1025 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
1026 }
1027 }
1028
1029 }
1030
1031 // shift sheets
1032 if (nDz)
1033 {
1034 if (nDz < 0)
1035 {
1036 TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
1037 TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
1038 // Remove sheets, if any, iDel or/and iTab may as well point to end().
1039 while (iDel != iTab)
1040 {
1041 iDel = aTableSlotsMap.erase(iDel);
1042 }
1043 // shift remaining down
1044 while (iTab != aTableSlotsMap.end())
1045 {
1046 SCTAB nTab = (*iTab).first + nDz;
1047 aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
1048 iTab = aTableSlotsMap.erase(iTab);
1049 }
1050 }
1051 else
1052 {
1053 TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
1054 if (iStop != aTableSlotsMap.end())
1055 {
1056 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
1057 if (!bStopIsBegin)
1058 --iStop;
1059 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
1060 --iTab;
1061 while (iTab != iStop)
1062 {
1063 SCTAB nTab = (*iTab).first + nDz;
1064 aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
1065 aTableSlotsMap.erase( iTab--);
1066 }
1067 // Shift the very first, iTab==iStop in this case.
1068 if (bStopIsBegin)
1069 {
1070 SCTAB nTab = (*iTab).first + nDz;
1071 aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
1072 aTableSlotsMap.erase( iStop);
1073 }
1074 }
1075 }
1076 }
1077
1078 // work off chain
1079 SCCOL nCol1, nCol2, theCol1, theCol2;
1080 SCROW nRow1, nRow2, theRow1, theRow2;
1081 SCTAB nTab1, nTab2, theTab1, theTab2;
1082 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1083 while ( pUpdateChain )
1084 {
1086 ScRange aRange( pArea->GetRange());
1088
1089 // update range
1090 aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
1091 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
1092 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
1093 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
1094 {
1095 aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
1096 pArea->UpdateRange( aRange );
1097 // For DDE and ScLookupCache
1098 pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );
1099 }
1100
1101 // insert to slots
1102 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
1103 {
1104 TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
1105 if (iTab == aTableSlotsMap.end())
1106 iTab = aTableSlotsMap.emplace( std::piecewise_construct,
1107 std::forward_as_tuple(nTab), std::forward_as_tuple(mnBcaSlots) ).first;
1108 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
1109 SCSIZE nStart, nEnd, nRowBreak;
1110 ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
1111 SCSIZE nOff = nStart;
1112 SCSIZE nBreak = nOff + nRowBreak;
1113 ScBroadcastAreaSlot** pp = ppSlots + nOff;
1114 while ( nOff <= nEnd )
1115 {
1116 if (!*pp)
1117 *pp = new ScBroadcastAreaSlot( pDoc, this );
1118 (*pp)->UpdateInsert( pArea );
1119 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
1120 }
1121 }
1122
1123 // unchain
1124 pArea->SetUpdateChainNext( nullptr );
1125 pArea->SetInUpdateChain( false );
1126
1127 // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
1128 // already executed in UpdateRemove().
1129 if (!pArea->GetRef())
1130 delete pArea;
1131 }
1132 pEOUpdateChain = nullptr;
1133}
1134
1136{
1138}
1139
1141{
1142 if (nInBulkBroadcast <= 0)
1143 return;
1144
1145 if (--nInBulkBroadcast == 0)
1146 {
1148 bool bBroadcasted = BulkBroadcastGroupAreas( nHintId );
1149 // Trigger the "final" tracking.
1151 pDoc->FinalTrackFormulas( nHintId );
1152 else if (bBroadcasted)
1153 pDoc->TrackFormulas( nHintId );
1154 }
1155}
1156
1158{
1159 return aBulkBroadcastAreas.insert( pArea ).second;
1160}
1161
1163{
1164 BulkGroupAreasType::iterator it = m_BulkGroupAreas.lower_bound(pArea);
1165 if (it == m_BulkGroupAreas.end() || m_BulkGroupAreas.key_comp()(pArea, it->first))
1166 {
1167 // Insert a new one.
1168 it = m_BulkGroupAreas.insert(it, std::make_pair(pArea, sc::ColumnSpanSet()));
1169 }
1170
1171 sc::ColumnSpanSet& rSet = it->second;
1172 rSet.set(*pDoc, rRange, true);
1173}
1174
1176{
1177 if (m_BulkGroupAreas.empty())
1178 return false;
1179
1180 sc::BulkDataHint aHint( *pDoc, nHintId);
1181
1182 bool bBroadcasted = false;
1183 for (const auto& [pArea, rSpans] : m_BulkGroupAreas)
1184 {
1185 assert(pArea);
1186 SvtBroadcaster& rBC = pArea->GetBroadcaster();
1187 if (!rBC.HasListeners())
1188 {
1189 /* FIXME: find the cause where the last listener is removed and
1190 * this area is still listed here. */
1191 SAL_WARN("sc.core","ScBroadcastAreaSlotMachine::BulkBroadcastGroupAreas - pArea has no listeners and should had been removed already");
1192 }
1193 else
1194 {
1195 aHint.setSpans(&rSpans);
1196 rBC.Broadcast(aHint);
1197 bBroadcasted = true;
1198 }
1199 }
1200
1201 m_BulkGroupAreas.clear();
1202
1203 return bBroadcasted;
1204}
1205
1207{
1208 return aBulkBroadcastAreas.erase( pArea );
1209}
1210
1212{
1213 m_BulkGroupAreas.erase(pArea);
1214}
1215
1217 ScBroadcastAreas::iterator& rIter )
1218{
1219 maAreasToBeErased.emplace_back( pSlot, rIter);
1220}
1221
1223{
1224 SAL_WARN_IF( pSlot->IsInBroadcastIteration(), "sc.core",
1225 "ScBroadcastAreaSlotMachine::FinallyEraseAreas: during iteration? NO!");
1226 if (pSlot->IsInBroadcastIteration())
1227 return;
1228
1229 // maAreasToBeErased is a simple vector so erasing an element may
1230 // invalidate iterators and would be inefficient anyway. Instead, copy
1231 // elements to be preserved (usually none!) to temporary vector and swap.
1232 AreasToBeErased aCopy;
1233 for (auto& rArea : maAreasToBeErased)
1234 {
1235 if (rArea.first == pSlot)
1236 pSlot->EraseArea( rArea.second);
1237 else
1238 aCopy.push_back( rArea);
1239 }
1240 maAreasToBeErased.swap( aCopy);
1241}
1242
1244 const ScRange& rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup )
1245{
1246 std::vector<sc::AreaListener> aRet;
1247
1248 SCTAB nEndTab = rRange.aEnd.Tab();
1249 for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
1250 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
1251 {
1252 ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
1253 SCSIZE nStart, nEnd, nRowBreak;
1254 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
1255 SCSIZE nOff = nStart;
1256 SCSIZE nBreak = nOff + nRowBreak;
1257 ScBroadcastAreaSlot** pp = ppSlots + nOff;
1258 while ( nOff <= nEnd )
1259 {
1260 ScBroadcastAreaSlot* p = *pp;
1261 if (p)
1262 p->GetAllListeners(rRange, aRet, eType, eGroup);
1263 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
1264 }
1265 }
1266
1267 return aRet;
1268}
1269
1271{
1272 for (const auto& [rTab, rTabSlots] : aTableSlotsMap)
1273 {
1274 (void)rTab;
1275
1276 ScBroadcastAreaSlot** pp = rTabSlots.getSlots();
1277 for (SCSIZE i = 0; i < mnBcaSlots; ++i)
1278 {
1279 const ScBroadcastAreaSlot* pSlot = pp[i];
1280 if (pSlot)
1281 pSlot->CollectBroadcasterState(rState);
1282 }
1283 }
1284}
1285
1286/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
#define BCA_LISTEN_ALWAYS
Definition: address.hxx:945
#define BCA_BRDCST_ALWAYS
Definition: address.hxx:944
static void ComputeNextSlot(SCSIZE &nOff, SCSIZE &nBreak, ScBroadcastAreaSlot **&pp, SCSIZE &nStart, ScBroadcastAreaSlot **const &ppSlots, SCSIZE nRowBreak, SCSIZE nBcaSlotsCol)
Definition: bcaslot.cxx:657
static void compare(SCSIZE value1, SCSIZE value2, int line)
Definition: bcaslot.cxx:675
std::unordered_set< const ScBroadcastArea *, ScBroadcastAreaBulkHash, ScBroadcastAreaBulkEqual > ScBroadcastAreasBulk
Definition: bcaslot.hxx:141
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
Slot offset arrangement of columns and rows, once per sheet.
Definition: bcaslot.hxx:266
std::unique_ptr< ScBroadcastAreaSlot *[]> ppSlots
Definition: bcaslot.hxx:275
BroadcastAreaSlots and their management, once per document.
Definition: bcaslot.hxx:249
bool BulkBroadcastGroupAreas(SfxHintId nHintId)
Definition: bcaslot.cxx:1175
ScBroadcastAreaSlotMachine(ScDocument *pDoc)
Definition: bcaslot.cxx:555
void ComputeAreaPoints(const ScRange &rRange, SCSIZE &nStart, SCSIZE &nEnd, SCSIZE &nRowBreak) const
Definition: bcaslot.cxx:647
BulkGroupAreasType m_BulkGroupAreas
Definition: bcaslot.hxx:312
AreasToBeErased maAreasToBeErased
Definition: bcaslot.hxx:314
void FinallyEraseAreas(ScBroadcastAreaSlot *pSlot)
Definition: bcaslot.cxx:1222
void LeaveBulkBroadcast(SfxHintId nHintId)
Definition: bcaslot.cxx:1140
ScBroadcastArea * GetEOUpdateChain() const
Definition: bcaslot.hxx:356
std::unique_ptr< SvtBroadcaster > pBCAlways
Definition: bcaslot.hxx:315
void SetEOUpdateChain(ScBroadcastArea *p)
Definition: bcaslot.hxx:357
std::vector< sc::AreaListener > GetAllListeners(const ScRange &rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup=sc::ListenerGroupType::Both)
Definition: bcaslot.cxx:1243
TableSlotsMap aTableSlotsMap
Definition: bcaslot.hxx:313
bool IsInBulkBroadcast() const
Definition: bcaslot.hxx:358
ScSlotDistribution maSlotDistribution
Definition: bcaslot.hxx:308
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: bcaslot.cxx:761
ScBroadcastAreasBulk aBulkBroadcastAreas
Definition: bcaslot.hxx:311
void UpdateBroadcastAreas(UpdateRefMode eUpdateRefMode, const ScRange &rRange, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: bcaslot.cxx:961
void EndListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: bcaslot.cxx:812
bool InsertBulkArea(const ScBroadcastArea *p)
Definition: bcaslot.cxx:1157
size_t RemoveBulkArea(const ScBroadcastArea *p)
Definition: bcaslot.cxx:1206
void CollectBroadcasterState(sc::BroadcasterState &rState) const
Definition: bcaslot.cxx:1270
void DelBroadcastAreasInRange(const ScRange &rRange)
Definition: bcaslot.cxx:924
ScBroadcastArea * pEOUpdateChain
Definition: bcaslot.hxx:318
ScBroadcastArea * pUpdateChain
Definition: bcaslot.hxx:317
bool AreaBroadcast(const ScRange &rRange, SfxHintId nHint)
Definition: bcaslot.cxx:863
::std::vector< ::std::pair< ScBroadcastAreaSlot *, ScBroadcastAreas::iterator > > AreasToBeErased
Definition: bcaslot.hxx:283
void RemoveBulkGroupArea(ScBroadcastArea *pArea)
Definition: bcaslot.cxx:1211
void SetUpdateChain(ScBroadcastArea *p)
Definition: bcaslot.hxx:355
void PushAreaToBeErased(ScBroadcastAreaSlot *pSlot, ScBroadcastAreas::iterator &rIter)
Definition: bcaslot.cxx:1216
void InsertBulkGroupArea(ScBroadcastArea *pArea, const ScRange &rRange)
Definition: bcaslot.cxx:1162
SCSIZE ComputeSlotOffset(const ScAddress &rAddress) const
Definition: bcaslot.cxx:619
Collection of BroadcastAreas.
Definition: bcaslot.hxx:147
ScBroadcastAreas::iterator FindBroadcastArea(const ScRange &rRange, bool bGroupListening)
Definition: bcaslot.cxx:178
bool IsInBroadcastIteration() const
Definition: bcaslot.hxx:227
void CollectBroadcasterState(sc::BroadcasterState &rState) const
Definition: bcaslot.cxx:501
void UpdateRemove(UpdateRefMode eUpdateRefMode, const ScRange &rRange, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: bcaslot.cxx:338
bool mbInBroadcastIteration
Definition: bcaslot.hxx:153
ScBroadcastArea aTmpSeekBroadcastArea
Definition: bcaslot.hxx:150
ScBroadcastAreas aBroadcastAreaTbl
Definition: bcaslot.hxx:149
void FinallyEraseAreas()
Finally erase all areas pushed as to-be-erased.
Definition: bcaslot.cxx:528
bool AreaBroadcast(const ScRange &rRange, SfxHintId nHint)
Definition: bcaslot.cxx:208
static bool isMarkedErased(const ScBroadcastAreas::const_iterator &rIter)
Definition: bcaslot.hxx:179
void UpdateRemoveArea(ScBroadcastArea *pArea)
Definition: bcaslot.cxx:382
ScBroadcastAreaSlot(ScDocument *pDoc, ScBroadcastAreaSlotMachine *pBASM)
Definition: bcaslot.cxx:43
void DelBroadcastAreasInRange(const ScRange &rRange)
Definition: bcaslot.cxx:314
ScDocument * pDoc
Definition: bcaslot.hxx:151
bool StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener, ScBroadcastArea *&rpArea)
Only here new ScBroadcastArea objects are created, prevention of dupes.
Definition: bcaslot.cxx:90
void InsertListeningArea(ScBroadcastArea *pArea)
Insert a ScBroadcastArea obtained via StartListeningArea() to subsequent slots.
Definition: bcaslot.cxx:134
ScBroadcastAreaSlotMachine * pBASM
Definition: bcaslot.hxx:152
void EraseArea(ScBroadcastAreas::iterator &rIter)
Erase an area from set and delete it if last reference, or if mbInBroadcastIteration is set push it t...
Definition: bcaslot.cxx:419
ScDocument::HardRecalcState CheckHardRecalcStateCondition() const
More hypothetical (memory would probably be doomed anyway) check whether there would be an overflow w...
Definition: bcaslot.cxx:69
void UpdateInsert(ScBroadcastArea *pArea)
Definition: bcaslot.cxx:396
bool mbHasErasedArea
If true, the slot has at least one area broadcaster marked for removal.
Definition: bcaslot.hxx:162
void EndListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener, ScBroadcastArea *&rpArea)
Definition: bcaslot.cxx:145
void GetAllListeners(const ScRange &rRange, std::vector< sc::AreaListener > &rListeners, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup)
Definition: bcaslot.cxx:440
Used in a Unique Associative Container.
Definition: bcaslot.hxx:57
ScBroadcastArea * GetUpdateChainNext() const
Definition: bcaslot.hxx:81
const ScRange & GetRange() const
Definition: bcaslot.hxx:77
bool IsInUpdateChain() const
Definition: bcaslot.hxx:83
ScBroadcastArea(const ScBroadcastArea &)=delete
void SetGroupListening(bool b)
Definition: bcaslot.hxx:87
void UpdateRange(const ScRange &rNewRange)
Definition: bcaslot.hxx:75
void SetInUpdateChain(bool b)
Definition: bcaslot.hxx:84
void SetUpdateChainNext(ScBroadcastArea *p)
Definition: bcaslot.hxx:82
sal_uLong GetRef() const
Definition: bcaslot.hxx:80
bool IsGroupListening() const
Definition: bcaslot.hxx:86
SvtBroadcaster & GetBroadcaster()
Definition: bcaslot.hxx:73
void IncRef()
Definition: bcaslot.hxx:78
sal_uLong DecRef()
Definition: bcaslot.hxx:79
void TrackFormulas(SfxHintId nHintId=SfxHintId::ScDataChanged)
Definition: documen7.cxx:524
void FinalTrackFormulas(SfxHintId nHintId)
Definition: documen7.cxx:503
bool ValidRow(SCROW nRow) const
Definition: document.hxx:900
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC SCROW GetMaxRowCount() const
Definition: document.hxx:895
HardRecalcState GetHardRecalcState() const
Definition: document.hxx:2402
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
bool IsDelayedFormulaGrouping() const
Definition: document.hxx:1425
@ ETERNAL
CalcAll() without broadcast/notify but setting up new listeners.
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:899
SC_DLLPUBLIC void SetAutoCalc(bool bNewAutoCalc)
Definition: documen7.cxx:602
void SetHardRecalcState(HardRecalcState eVal)
Definition: document.hxx:2403
SC_DLLPUBLIC SCCOL GetMaxColCount() const
Definition: document.hxx:894
bool IsTrackFormulasPending() const
Definition: document.hxx:2397
ScRange GetRange() const
Definition: brdcst.hxx:33
SCROW GetRowCount() const
Definition: brdcst.hxx:32
const ScAddress & GetStartAddress() const
Definition: brdcst.hxx:31
ScRange Intersection(const ScRange &rOther) const
Definition: address.cxx:1547
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
ScAddress aEnd
Definition: address.hxx:498
bool Intersects(const ScRange &rRange) const
Definition: address.hxx:734
bool Contains(const ScAddress &) const
is Address& fully in Range?
Definition: address.hxx:718
bool IsValid() const
Definition: address.hxx:544
ScAddress aStart
Definition: address.hxx:497
static ScRefUpdateRes Update(const ScDocument *pDoc, UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz, SCCOL &theCol1, SCROW &theRow1, SCTAB &theTab1, SCCOL &theCol2, SCROW &theRow2, SCTAB &theTab2)
Definition: refupdat.cxx:188
void SetError(ErrCode rErr)
bool HasListeners() const
void Broadcast(const SfxHint &rHint)
std::vector< SvtListener * > ListenersType
ListenersType & GetAllListeners()
bool StartListening(SvtBroadcaster &rBroadcaster)
void EndListening(SvtBroadcaster &rBroadcaster)
void setSpans(const ColumnSpanSet *pSpans)
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
sal_Int32 nRefCount
FilterGroup & rTarget
DocumentType eType
UpdateRefMode
Definition: global.hxx:301
SfxHintId
void * p
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
int i
line
AreaOverlapType
Definition: types.hxx:110
ListenerGroupType
Definition: types.hxx:118
#define SCWARN_CORE_HARD_RECALC
Definition: scerrors.hxx:78
static SfxItemSet & rSet
bool mbGroupListening
Definition: bcaslot.hxx:46
ScRange maArea
Definition: bcaslot.hxx:45
SvtListener * mpListener
Definition: bcaslot.hxx:47
std::map< ScRange, std::vector< AreaListener > > aAreaListenerStore
Definition: broadcast.hxx:65
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17