Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx
Warning:line 515, column 9
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name atrftn.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx

/home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx

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 <fmtftn.hxx>
21
22#include <doc.hxx>
23#include <DocumentContentOperationsManager.hxx>
24#include <IDocumentStylePoolAccess.hxx>
25#include <cntfrm.hxx>
26#include <rootfrm.hxx>
27#include <pagefrm.hxx>
28#include <txtftn.hxx>
29#include <ftnidx.hxx>
30#include <ftninfo.hxx>
31#include <ndtxt.hxx>
32#include <poolfmt.hxx>
33#include <ftnfrm.hxx>
34#include <ndindex.hxx>
35#include <fmtftntx.hxx>
36#include <section.hxx>
37#include <calbck.hxx>
38#include <hints.hxx>
39#include <pam.hxx>
40#include <rtl/ustrbuf.hxx>
41#include <vcl/svapp.hxx>
42#include <unotextrange.hxx>
43
44namespace {
45 /// Get a sorted list of the used footnote reference numbers.
46 /// @param[in] rDoc The active document.
47 /// @param[in] pExclude A footnote whose reference number should be excluded from the set.
48 /// @param[out] rUsedRef The set of used reference numbers.
49 /// @param[out] rInvalid A returned list of all items that had an invalid reference number.
50 void lcl_FillUsedFootnoteRefNumbers(SwDoc &rDoc,
51 SwTextFootnote const *pExclude,
52 std::set<sal_uInt16> &rUsedRef,
53 std::vector<SwTextFootnote*> &rInvalid)
54 {
55 SwFootnoteIdxs& ftnIdxs = rDoc.GetFootnoteIdxs();
56
57 rInvalid.clear();
58
59 for( size_t n = 0; n < ftnIdxs.size(); ++n )
60 {
61 SwTextFootnote* pTextFootnote = ftnIdxs[ n ];
62 if ( pTextFootnote != pExclude )
63 {
64 if ( USHRT_MAX(32767 *2 +1) == pTextFootnote->GetSeqRefNo() )
65 {
66 rInvalid.push_back(pTextFootnote);
67 }
68 else
69 {
70 rUsedRef.insert( pTextFootnote->GetSeqRefNo() );
71 }
72 }
73 }
74 }
75
76 /// Check whether a requested reference number is available.
77 /// @param[in] rUsedNums Set of used reference numbers.
78 /// @param[in] requested The requested reference number.
79 /// @returns true if the number is available, false if not.
80 bool lcl_IsRefNumAvailable(std::set<sal_uInt16> const &rUsedNums,
81 sal_uInt16 requested)
82 {
83 if ( USHRT_MAX(32767 *2 +1) == requested )
84 return false; // Invalid sequence number.
85 if ( rUsedNums.count(requested) )
86 return false; // Number already used.
87 return true;
88 }
89
90 /// Get the first few unused sequential reference numbers.
91 /// @param[out] rLowestUnusedNums The lowest unused sequential reference numbers.
92 /// @param[in] rUsedNums The set of used sequential reference numbers.
93 /// @param[in] numRequired The number of reference number required.
94 void lcl_FillUnusedSeqRefNums(std::vector<sal_uInt16> &rLowestUnusedNums,
95 const std::set<sal_uInt16> &rUsedNums,
96 size_t numRequired)
97 {
98 if (!numRequired)
99 return;
100
101 rLowestUnusedNums.reserve(numRequired);
102 sal_uInt16 newNum = 0;
103 //Start by using numbers from gaps in rUsedNums
104 for( const auto& rNum : rUsedNums )
105 {
106 while ( newNum < rNum )
107 {
108 rLowestUnusedNums.push_back( newNum++ );
109 if ( --numRequired == 0)
110 return;
111 }
112 newNum++;
113 }
114 //Filled in all gaps. Fill the rest of the list with new numbers.
115 do
116 {
117 rLowestUnusedNums.push_back( newNum++ );
118 }
119 while ( --numRequired > 0 );
120 }
121
122}
123
124SwFormatFootnote::SwFormatFootnote( bool bEndNote )
125 : SfxPoolItem( RES_TXTATR_FTN )
126 , SwModify()
127 , m_pTextAttr(nullptr)
128 , m_nNumber(0)
129 , m_nNumberRLHidden(0)
130 , m_bEndNote(bEndNote)
131{
132}
133
134bool SwFormatFootnote::operator==( const SfxPoolItem& rAttr ) const
135{
136 assert(SfxPoolItem::operator==(rAttr))(static_cast <bool> (SfxPoolItem::operator==(rAttr)) ? void
(0) : __assert_fail ("SfxPoolItem::operator==(rAttr)", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx"
, 136, __extension__ __PRETTY_FUNCTION__))
;
137 return m_nNumber == static_cast<const SwFormatFootnote&>(rAttr).m_nNumber &&
138 //FIXME?
139 m_aNumber == static_cast<const SwFormatFootnote&>(rAttr).m_aNumber &&
140 m_bEndNote == static_cast<const SwFormatFootnote&>(rAttr).m_bEndNote;
141}
142
143SwFormatFootnote* SwFormatFootnote::Clone( SfxItemPool* ) const
144{
145 SwFormatFootnote* pNew = new SwFormatFootnote;
146 pNew->m_aNumber = m_aNumber;
147 pNew->m_nNumber = m_nNumber;
148 pNew->m_nNumberRLHidden = m_nNumberRLHidden;
149 pNew->m_bEndNote = m_bEndNote;
150 return pNew;
151}
152
153void SwFormatFootnote::Modify(SfxPoolItem const* pOld, SfxPoolItem const* pNew)
154{
155 NotifyClients(pOld, pNew);
156 if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
157 { // invalidate cached UNO object
158 SetXFootnote(css::uno::Reference<css::text::XFootnote>(nullptr));
159 }
160}
161
162void SwFormatFootnote::InvalidateFootnote()
163{
164 SwPtrMsgPoolItem const item(RES_REMOVE_UNO_OBJECT,
165 &static_cast<SwModify&>(*this)); // cast to base class (void*)
166 NotifyClients(&item, &item);
167}
168
169void SwFormatFootnote::SetEndNote( bool b )
170{
171 if ( b != m_bEndNote )
1
Assuming 'b' is not equal to field 'm_bEndNote'
2
Taking true branch
172 {
173 if ( GetTextFootnote() )
3
Assuming the condition is true
4
Taking true branch
174 {
175 GetTextFootnote()->DelFrames(nullptr);
5
Calling 'SwTextFootnote::DelFrames'
176 }
177 m_bEndNote = b;
178 }
179}
180
181SwFormatFootnote::~SwFormatFootnote()
182{
183}
184
185OUString SwFormatFootnote::GetFootnoteText(SwRootFrame const& rLayout) const
186{
187 OUStringBuffer buf;
188 if( m_pTextAttr->GetStartNode() )
189 {
190 SwNodeIndex aIdx( *m_pTextAttr->GetStartNode(), 1 );
191 SwContentNode* pCNd = aIdx.GetNode().GetTextNode();
192 if( !pCNd )
193 pCNd = aIdx.GetNodes().GoNext( &aIdx );
194
195 if( pCNd->IsTextNode() ) {
196 buf.append(static_cast<SwTextNode*>(pCNd)->GetExpandText(&rLayout));
197
198 ++aIdx;
199 while ( !aIdx.GetNode().IsEndNode() ) {
200 if ( aIdx.GetNode().IsTextNode() )
201 {
202 buf.append(" ");
203 buf.append(aIdx.GetNode().GetTextNode()->GetExpandText(&rLayout));
204 }
205 ++aIdx;
206 }
207 }
208 }
209 return buf.makeStringAndClear();
210}
211
212/// return the view string of the foot/endnote
213OUString SwFormatFootnote::GetViewNumStr(const SwDoc& rDoc,
214 SwRootFrame const*const pLayout, bool bInclStrings) const
215{
216 OUString sRet( GetNumStr() );
217 if( sRet.isEmpty() )
218 {
219 // in this case the number is needed, get it via SwDoc's FootnoteInfo
220 bool bMakeNum = true;
221 const SwSectionNode* pSectNd = m_pTextAttr
222 ? SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *m_pTextAttr )
223 : nullptr;
224 sal_uInt16 const nNumber(pLayout && pLayout->IsHideRedlines()
225 ? GetNumberRLHidden()
226 : GetNumber());
227
228 if( pSectNd )
229 {
230 const SwFormatFootnoteEndAtTextEnd& rFootnoteEnd = static_cast<const SwFormatFootnoteEndAtTextEnd&>(
231 pSectNd->GetSection().GetFormat()->GetFormatAttr(
232 IsEndNote() ?
233 static_cast<sal_uInt16>(RES_END_AT_TXTEND) :
234 static_cast<sal_uInt16>(RES_FTN_AT_TXTEND) ) );
235
236 if( FTNEND_ATTXTEND_OWNNUMANDFMT == rFootnoteEnd.GetValue() )
237 {
238 bMakeNum = false;
239 sRet = rFootnoteEnd.GetSwNumType().GetNumStr( nNumber );
240 if( bInclStrings )
241 {
242 sRet = rFootnoteEnd.GetPrefix() + sRet + rFootnoteEnd.GetSuffix();
243 }
244 }
245 }
246
247 if( bMakeNum )
248 {
249 const SwEndNoteInfo* pInfo;
250 if( IsEndNote() )
251 pInfo = &rDoc.GetEndNoteInfo();
252 else
253 pInfo = &rDoc.GetFootnoteInfo();
254 sRet = pInfo->m_aFormat.GetNumStr( nNumber );
255 if( bInclStrings )
256 {
257 sRet = pInfo->GetPrefix() + sRet + pInfo->GetSuffix();
258 }
259 }
260 }
261 return sRet;
262}
263
264uno::Reference<text::XTextRange> SwFormatFootnote::getAnchor(SwDoc& rDoc) const
265{
266 SolarMutexGuard aGuard;
267 if (!m_pTextAttr)
268 return uno::Reference<text::XTextRange>();
269 SwPaM aPam(m_pTextAttr->GetTextNode(), m_pTextAttr->GetStart());
270 aPam.SetMark();
271 ++aPam.GetMark()->nContent;
272 const uno::Reference<text::XTextRange> xRet =
273 SwXTextRange::CreateXTextRange(rDoc, *aPam.Start(), aPam.End());
274 return xRet;
275}
276
277SwTextFootnote::SwTextFootnote( SwFormatFootnote& rAttr, sal_Int32 nStartPos )
278 : SwTextAttr( rAttr, nStartPos )
279 , m_pTextNode( nullptr )
280 , m_nSeqNo( USHRT_MAX(32767 *2 +1) )
281{
282 rAttr.m_pTextAttr = this;
283 SetHasDummyChar(true);
284}
285
286SwTextFootnote::~SwTextFootnote()
287{
288 SetStartNode( nullptr );
289}
290
291void SwTextFootnote::SetStartNode( const SwNodeIndex *pNewNode, bool bDelNode )
292{
293 if( pNewNode )
294 {
295 if ( !m_pStartNode )
296 {
297 m_pStartNode.reset(new SwNodeIndex(*pNewNode));
298 }
299 else
300 {
301 *m_pStartNode = *pNewNode;
302 }
303 }
304 else if ( m_pStartNode )
305 {
306 // need to do 2 things:
307 // 1) unregister footnotes at their pages
308 // 2) delete the footnote section in the Inserts of the nodes-array
309 SwDoc* pDoc;
310 if ( m_pTextNode )
311 {
312 pDoc = &m_pTextNode->GetDoc();
313 }
314 else
315 {
316 //JP 27.01.97: the sw3-Reader creates a StartNode but the
317 // attribute isn't anchored in the TextNode yet.
318 // If it is deleted (e.g. Insert File with footnote
319 // inside fly frame), the content must also be deleted.
320 pDoc = &m_pStartNode->GetNodes().GetDoc();
321 }
322
323 // If called from ~SwDoc(), must not delete the footnote nodes,
324 // and not necessary to delete the footnote frames.
325 if( !pDoc->IsInDtor() )
326 {
327 if( bDelNode )
328 {
329 // 2) delete the section for the footnote nodes
330 // it's possible that the Inserts have already been deleted (how???)
331 pDoc->getIDocumentContentOperations().DeleteSection( &m_pStartNode->GetNode() );
332 }
333 else
334 // If the nodes are not deleted, their frames must be removed
335 // from the page (deleted), there is nothing else that deletes
336 // them (particularly not Undo)
337 DelFrames( nullptr );
338 }
339 m_pStartNode.reset();
340
341 // remove the footnote from the SwDoc's array
342 for( size_t n = 0; n < pDoc->GetFootnoteIdxs().size(); ++n )
343 if( this == pDoc->GetFootnoteIdxs()[n] )
344 {
345 pDoc->GetFootnoteIdxs().erase( pDoc->GetFootnoteIdxs().begin() + n );
346 // if necessary, update following footnotes
347 if( !pDoc->IsInDtor() && n < pDoc->GetFootnoteIdxs().size() )
348 {
349 SwNodeIndex aTmp( pDoc->GetFootnoteIdxs()[n]->GetTextNode() );
350 pDoc->GetFootnoteIdxs().UpdateFootnote( aTmp );
351 }
352 break;
353 }
354 }
355}
356
357void SwTextFootnote::SetNumber(const sal_uInt16 nNewNum,
358 sal_uInt16 const nNumberRLHidden, const OUString &sNumStr)
359{
360 SwFormatFootnote& rFootnote = const_cast<SwFormatFootnote&>(GetFootnote());
361
362 rFootnote.m_aNumber = sNumStr;
363 if ( sNumStr.isEmpty() )
364 {
365 rFootnote.m_nNumber = nNewNum;
366 rFootnote.m_nNumberRLHidden = nNumberRLHidden;
367 }
368 InvalidateNumberInLayout();
369}
370
371void SwTextFootnote::InvalidateNumberInLayout()
372{
373 assert(m_pTextNode)(static_cast <bool> (m_pTextNode) ? void (0) : __assert_fail
("m_pTextNode", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx"
, 373, __extension__ __PRETTY_FUNCTION__))
;
374 SwFormatFootnote const& rFootnote(GetFootnote());
375 SwNodes &rNodes = m_pTextNode->GetDoc().GetNodes();
376 m_pTextNode->ModifyNotification( nullptr, &rFootnote );
377 if ( m_pStartNode )
378 {
379 // must iterate over all TextNodes because of footnotes on other pages
380 sal_uLong nSttIdx = m_pStartNode->GetIndex() + 1;
381 sal_uLong nEndIdx = m_pStartNode->GetNode().EndOfSectionIndex();
382 for( ; nSttIdx < nEndIdx; ++nSttIdx )
383 {
384 SwNode* pNd;
385 if( ( pNd = rNodes[ nSttIdx ] )->IsTextNode() )
386 static_cast<SwTextNode*>(pNd)->ModifyNotification( nullptr, &rFootnote );
387 }
388 }
389}
390
391void SwTextFootnote::CopyFootnote(
392 SwTextFootnote & rDest,
393 SwTextNode & rDestNode ) const
394{
395 if (m_pStartNode && !rDest.GetStartNode())
396 {
397 // dest missing node section? create it here!
398 // (happens in SwTextNode::CopyText if pDest == this)
399 rDest.MakeNewTextSection( rDestNode.GetNodes() );
400 }
401 if (m_pStartNode && rDest.GetStartNode())
402 {
403 // footnotes not necessarily in same document!
404 SwDoc& rDstDoc = rDestNode.GetDoc();
405 SwNodes &rDstNodes = rDstDoc.GetNodes();
406
407 // copy only the content of the section
408 SwNodeRange aRg( *m_pStartNode, 1,
409 *m_pStartNode->GetNode().EndOfSectionNode() );
410
411 // insert at the end of rDest, i.e., the nodes are appended.
412 // nDestLen contains number of ContentNodes in rDest _before_ copy.
413 SwNodeIndex aStart( *(rDest.GetStartNode()) );
414 SwNodeIndex aEnd( *aStart.GetNode().EndOfSectionNode() );
415 sal_uLong nDestLen = aEnd.GetIndex() - aStart.GetIndex() - 1;
416
417 m_pTextNode->GetDoc().GetDocumentContentOperationsManager().CopyWithFlyInFly(aRg, aEnd);
418
419 // in case the destination section was not empty, delete the old nodes
420 // before: Src: SxxxE, Dst: SnE
421 // now: Src: SxxxE, Dst: SnxxxE
422 // after: Src: SxxxE, Dst: SxxxE
423 ++aStart;
424 rDstNodes.Delete( aStart, nDestLen );
425 }
426
427 // also copy user defined number string
428 if( !GetFootnote().m_aNumber.isEmpty() )
429 {
430 const_cast<SwFormatFootnote &>(rDest.GetFootnote()).m_aNumber = GetFootnote().m_aNumber;
431 }
432}
433
434/// create a new nodes-array section for the footnote
435void SwTextFootnote::MakeNewTextSection( SwNodes& rNodes )
436{
437 if ( m_pStartNode )
438 return;
439
440 // set the footnote style on the SwTextNode
441 SwTextFormatColl *pFormatColl;
442 const SwEndNoteInfo* pInfo;
443 sal_uInt16 nPoolId;
444
445 if( GetFootnote().IsEndNote() )
446 {
447 pInfo = &rNodes.GetDoc().GetEndNoteInfo();
448 nPoolId = RES_POOLCOLL_ENDNOTE;
449 }
450 else
451 {
452 pInfo = &rNodes.GetDoc().GetFootnoteInfo();
453 nPoolId = RES_POOLCOLL_FOOTNOTE;
454 }
455
456 pFormatColl = pInfo->GetFootnoteTextColl();
457 if( nullptr == pFormatColl )
458 pFormatColl = rNodes.GetDoc().getIDocumentStylePoolAccess().GetTextCollFromPool( nPoolId );
459
460 SwStartNode* pSttNd = rNodes.MakeTextSection( SwNodeIndex( rNodes.GetEndOfInserts() ),
461 SwFootnoteStartNode, pFormatColl );
462 m_pStartNode.reset(new SwNodeIndex(*pSttNd));
463}
464
465void SwTextFootnote::DelFrames(SwRootFrame const*const pRoot)
466{
467 // delete the FootnoteFrames from the pages
468 OSL_ENSURE( m_pTextNode, "SwTextFootnote: where is my TextNode?" )do { if (true && (!(m_pTextNode))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx"
":" "468" ": "), "%s", "SwTextFootnote: where is my TextNode?"
); } } while (false)
;
6
Assuming field 'm_pTextNode' is non-null
7
Taking false branch
8
Loop condition is false. Exiting loop
469 if ( !m_pTextNode
8.1
Field 'm_pTextNode' is non-null
8.1
Field 'm_pTextNode' is non-null
8.1
Field 'm_pTextNode' is non-null
8.1
Field 'm_pTextNode' is non-null
8.1
Field 'm_pTextNode' is non-null
)
9
Taking false branch
470 return;
471
472 bool bFrameFnd = false;
473 {
474 SwIterator<SwContentFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*m_pTextNode);
475 for( SwContentFrame* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
10
Loop condition is false. Execution continues on line 322
476 {
477 if( pRoot != pFnd->getRootFrame() && pRoot )
478 continue;
479 SwPageFrame* pPage = pFnd->FindPageFrame();
480 if( pPage )
481 {
482 // note: we have found the correct frame only if the footnote
483 // was actually removed; in case this is called from
484 // SwTextFrame::DestroyImpl(), then that frame isn't connected
485 // to SwPageFrame any more, and RemoveFootnote on any follow
486 // must not prevent the fall-back to the !bFrameFnd code.
487 bFrameFnd = pPage->RemoveFootnote(pFnd, this);
488 }
489 }
490 }
491 //JP 13.05.97: if the layout is deleted before the footnotes are deleted,
492 // try to delete the footnote's frames by another way
493 if ( bFrameFnd
10.1
'bFrameFnd' is false
10.1
'bFrameFnd' is false
10.1
'bFrameFnd' is false
10.1
'bFrameFnd' is false
10.1
'bFrameFnd' is false
|| !m_pStartNode )
11
Calling 'unique_ptr::operator bool'
15
Returning from 'unique_ptr::operator bool'
16
Taking false branch
494 return;
495
496 SwNodeIndex aIdx( *m_pStartNode );
497 SwContentNode* pCNd = m_pTextNode->GetNodes().GoNext( &aIdx );
498 if( !pCNd )
17
Assuming 'pCNd' is non-null
18
Taking false branch
499 return;
500
501 SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pCNd);
19
Calling constructor for 'SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>'
34
Returning from constructor for 'SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>'
502 for( SwContentFrame* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
35
Calling 'SwIterator::First'
39
Returning from 'SwIterator::First'
40
Loop condition is true. Entering loop body
503 {
504 if( pRoot != pFnd->getRootFrame() && pRoot )
41
Assuming the condition is false
505 continue;
506 SwPageFrame* pPage = pFnd->FindPageFrame();
507
508 SwFrame *pFrame = pFnd->GetUpper();
42
'pFrame' initialized here
509 while ( pFrame && !pFrame->IsFootnoteFrame() )
43
Assuming 'pFrame' is null
510 pFrame = pFrame->GetUpper();
511
512 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pFrame);
44
'pFootnote' initialized to a null pointer value
513 while ( pFootnote
44.1
'pFootnote' is null
44.1
'pFootnote' is null
44.1
'pFootnote' is null
44.1
'pFootnote' is null
44.1
'pFootnote' is null
&& pFootnote->GetMaster() )
514 pFootnote = pFootnote->GetMaster();
515 OSL_ENSURE( pFootnote->GetAttr() == this, "Footnote mismatch error." )do { if (true && (!(pFootnote->GetAttr() == this))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx"
":" "515" ": "), "%s", "Footnote mismatch error."); } } while
(false)
;
45
Called C++ object pointer is null
516
517 while ( pFootnote )
518 {
519 SwFootnoteFrame *pFoll = pFootnote->GetFollow();
520 pFootnote->Cut();
521 SwFrame::DestroyFrame(pFootnote);
522 pFootnote = pFoll;
523 }
524
525 // #i20556# During hiding of a section, the connection
526 // to the layout is already lost. pPage may be 0:
527 if ( pPage )
528 pPage->UpdateFootnoteNum();
529 }
530}
531
532/// Set the sequence number for the current footnote.
533/// @returns The new sequence number or USHRT_MAX if invalid.
534void SwTextFootnote::SetSeqRefNo()
535{
536 if( !m_pTextNode )
537 return;
538
539 SwDoc& rDoc = m_pTextNode->GetDoc();
540 if( rDoc.IsInReading() )
541 return;
542
543 std::set<sal_uInt16> aUsedNums;
544 std::vector<SwTextFootnote*> badRefNums;
545 ::lcl_FillUsedFootnoteRefNumbers(rDoc, this, aUsedNums, badRefNums);
546 if ( ::lcl_IsRefNumAvailable(aUsedNums, m_nSeqNo) )
547 return;
548 std::vector<sal_uInt16> unused;
549 ::lcl_FillUnusedSeqRefNums(unused, aUsedNums, 1);
550 m_nSeqNo = unused[0];
551}
552
553/// Set a unique sequential reference number for every footnote in the document.
554/// @param[in] rDoc The document to be processed.
555void SwTextFootnote::SetUniqueSeqRefNo( SwDoc& rDoc )
556{
557 std::set<sal_uInt16> aUsedNums;
558 std::vector<SwTextFootnote*> badRefNums;
559 ::lcl_FillUsedFootnoteRefNumbers(rDoc, nullptr, aUsedNums, badRefNums);
560 std::vector<sal_uInt16> aUnused;
561 ::lcl_FillUnusedSeqRefNums(aUnused, aUsedNums, badRefNums.size());
562
563 for (size_t i = 0; i < badRefNums.size(); ++i)
564 {
565 badRefNums[i]->m_nSeqNo = aUnused[i];
566 }
567}
568
569void SwTextFootnote::CheckCondColl()
570{
571//FEATURE::CONDCOLL
572 if( GetStartNode() )
573 static_cast<SwStartNode&>(GetStartNode()->GetNode()).CheckSectionCondColl();
574//FEATURE::CONDCOLL
575}
576
577/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/unique_ptr.h

1// unique_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2008-2020 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/unique_ptr.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _UNIQUE_PTR_H1
31#define _UNIQUE_PTR_H1 1
32
33#include <bits/c++config.h>
34#include <debug/assertions.h>
35#include <type_traits>
36#include <utility>
37#include <tuple>
38#include <bits/stl_function.h>
39#include <bits/functional_hash.h>
40#if __cplusplus201703L > 201703L
41# include <compare>
42# include <ostream>
43#endif
44
45namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup pointer_abstractions
51 * @{
52 */
53
54#if _GLIBCXX_USE_DEPRECATED1
55#pragma GCC diagnostic push
56#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57 template<typename> class auto_ptr;
58#pragma GCC diagnostic pop
59#endif
60
61 /// Primary template of default_delete, used by unique_ptr for single objects
62 template<typename _Tp>
63 struct default_delete
64 {
65 /// Default constructor
66 constexpr default_delete() noexcept = default;
67
68 /** @brief Converting constructor.
69 *
70 * Allows conversion from a deleter for objects of another type, `_Up`,
71 * only if `_Up*` is convertible to `_Tp*`.
72 */
73 template<typename _Up,
74 typename = _Require<is_convertible<_Up*, _Tp*>>>
75 default_delete(const default_delete<_Up>&) noexcept { }
76
77 /// Calls `delete __ptr`
78 void
79 operator()(_Tp* __ptr) const
80 {
81 static_assert(!is_void<_Tp>::value,
82 "can't delete pointer to incomplete type");
83 static_assert(sizeof(_Tp)>0,
84 "can't delete pointer to incomplete type");
85 delete __ptr;
86 }
87 };
88
89 // _GLIBCXX_RESOLVE_LIB_DEFECTS
90 // DR 740 - omit specialization for array objects with a compile time length
91
92 /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>`
93 template<typename _Tp>
94 struct default_delete<_Tp[]>
95 {
96 public:
97 /// Default constructor
98 constexpr default_delete() noexcept = default;
99
100 /** @brief Converting constructor.
101 *
102 * Allows conversion from a deleter for arrays of another type, such as
103 * a const-qualified version of `_Tp`.
104 *
105 * Conversions from types derived from `_Tp` are not allowed because
106 * it is undefined to `delete[]` an array of derived types through a
107 * pointer to the base type.
108 */
109 template<typename _Up,
110 typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
111 default_delete(const default_delete<_Up[]>&) noexcept { }
112
113 /// Calls `delete[] __ptr`
114 template<typename _Up>
115 typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
116 operator()(_Up* __ptr) const
117 {
118 static_assert(sizeof(_Tp)>0,
119 "can't delete pointer to incomplete type");
120 delete [] __ptr;
121 }
122 };
123
124 /// @cond undocumented
125
126 // Manages the pointer and deleter of a unique_ptr
127 template <typename _Tp, typename _Dp>
128 class __uniq_ptr_impl
129 {
130 template <typename _Up, typename _Ep, typename = void>
131 struct _Ptr
132 {
133 using type = _Up*;
134 };
135
136 template <typename _Up, typename _Ep>
137 struct
138 _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
139 {
140 using type = typename remove_reference<_Ep>::type::pointer;
141 };
142
143 public:
144 using _DeleterConstraint = enable_if<
145 __and_<__not_<is_pointer<_Dp>>,
146 is_default_constructible<_Dp>>::value>;
147
148 using pointer = typename _Ptr<_Tp, _Dp>::type;
149
150 static_assert( !is_rvalue_reference<_Dp>::value,
151 "unique_ptr's deleter type must be a function object type"
152 " or an lvalue reference type" );
153
154 __uniq_ptr_impl() = default;
155 __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
156
157 template<typename _Del>
158 __uniq_ptr_impl(pointer __p, _Del&& __d)
159 : _M_t(__p, std::forward<_Del>(__d)) { }
160
161 __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
162 : _M_t(std::move(__u._M_t))
163 { __u._M_ptr() = nullptr; }
164
165 __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
166 {
167 reset(__u.release());
168 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
169 return *this;
170 }
171
172 pointer& _M_ptr() { return std::get<0>(_M_t); }
173 pointer _M_ptr() const { return std::get<0>(_M_t); }
174 _Dp& _M_deleter() { return std::get<1>(_M_t); }
175 const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
176
177 void reset(pointer __p) noexcept
178 {
179 const pointer __old_p = _M_ptr();
180 _M_ptr() = __p;
181 if (__old_p)
182 _M_deleter()(__old_p);
183 }
184
185 pointer release() noexcept
186 {
187 pointer __p = _M_ptr();
188 _M_ptr() = nullptr;
189 return __p;
190 }
191
192 void
193 swap(__uniq_ptr_impl& __rhs) noexcept
194 {
195 using std::swap;
196 swap(this->_M_ptr(), __rhs._M_ptr());
197 swap(this->_M_deleter(), __rhs._M_deleter());
198 }
199
200 private:
201 tuple<pointer, _Dp> _M_t;
202 };
203
204 // Defines move construction + assignment as either defaulted or deleted.
205 template <typename _Tp, typename _Dp,
206 bool = is_move_constructible<_Dp>::value,
207 bool = is_move_assignable<_Dp>::value>
208 struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>
209 {
210 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
211 __uniq_ptr_data(__uniq_ptr_data&&) = default;
212 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
213 };
214
215 template <typename _Tp, typename _Dp>
216 struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp>
217 {
218 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
219 __uniq_ptr_data(__uniq_ptr_data&&) = default;
220 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
221 };
222
223 template <typename _Tp, typename _Dp>
224 struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp>
225 {
226 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
227 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
228 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
229 };
230
231 template <typename _Tp, typename _Dp>
232 struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp>
233 {
234 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
235 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
236 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
237 };
238 /// @endcond
239
240 /// 20.7.1.2 unique_ptr for single objects.
241 template <typename _Tp, typename _Dp = default_delete<_Tp>>
242 class unique_ptr
243 {
244 template <typename _Up>
245 using _DeleterConstraint =
246 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
247
248 __uniq_ptr_data<_Tp, _Dp> _M_t;
249
250 public:
251 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
252 using element_type = _Tp;
253 using deleter_type = _Dp;
254
255 private:
256 // helper template for detecting a safe conversion from another
257 // unique_ptr
258 template<typename _Up, typename _Ep>
259 using __safe_conversion_up = __and_<
260 is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
261 __not_<is_array<_Up>>
262 >;
263
264 public:
265 // Constructors.
266
267 /// Default constructor, creates a unique_ptr that owns nothing.
268 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
269 constexpr unique_ptr() noexcept
270 : _M_t()
271 { }
272
273 /** Takes ownership of a pointer.
274 *
275 * @param __p A pointer to an object of @c element_type
276 *
277 * The deleter will be value-initialized.
278 */
279 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
280 explicit
281 unique_ptr(pointer __p) noexcept
282 : _M_t(__p)
283 { }
284
285 /** Takes ownership of a pointer.
286 *
287 * @param __p A pointer to an object of @c element_type
288 * @param __d A reference to a deleter.
289 *
290 * The deleter will be initialized with @p __d
291 */
292 template<typename _Del = deleter_type,
293 typename = _Require<is_copy_constructible<_Del>>>
294 unique_ptr(pointer __p, const deleter_type& __d) noexcept
295 : _M_t(__p, __d) { }
296
297 /** Takes ownership of a pointer.
298 *
299 * @param __p A pointer to an object of @c element_type
300 * @param __d An rvalue reference to a (non-reference) deleter.
301 *
302 * The deleter will be initialized with @p std::move(__d)
303 */
304 template<typename _Del = deleter_type,
305 typename = _Require<is_move_constructible<_Del>>>
306 unique_ptr(pointer __p,
307 __enable_if_t<!is_lvalue_reference<_Del>::value,
308 _Del&&> __d) noexcept
309 : _M_t(__p, std::move(__d))
310 { }
311
312 template<typename _Del = deleter_type,
313 typename _DelUnref = typename remove_reference<_Del>::type>
314 unique_ptr(pointer,
315 __enable_if_t<is_lvalue_reference<_Del>::value,
316 _DelUnref&&>) = delete;
317
318 /// Creates a unique_ptr that owns nothing.
319 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
320 constexpr unique_ptr(nullptr_t) noexcept
321 : _M_t()
322 { }
323
324 // Move constructors.
325
326 /// Move constructor.
327 unique_ptr(unique_ptr&&) = default;
328
329 /** @brief Converting constructor from another type
330 *
331 * Requires that the pointer owned by @p __u is convertible to the
332 * type of pointer owned by this object, @p __u does not own an array,
333 * and @p __u has a compatible deleter type.
334 */
335 template<typename _Up, typename _Ep, typename = _Require<
336 __safe_conversion_up<_Up, _Ep>,
337 typename conditional<is_reference<_Dp>::value,
338 is_same<_Ep, _Dp>,
339 is_convertible<_Ep, _Dp>>::type>>
340 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
341 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
342 { }
343
344#if _GLIBCXX_USE_DEPRECATED1
345#pragma GCC diagnostic push
346#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
347 /// Converting constructor from @c auto_ptr
348 template<typename _Up, typename = _Require<
349 is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
350 unique_ptr(auto_ptr<_Up>&& __u) noexcept;
351#pragma GCC diagnostic pop
352#endif
353
354 /// Destructor, invokes the deleter if the stored pointer is not null.
355 ~unique_ptr() noexcept
356 {
357 static_assert(__is_invocable<deleter_type&, pointer>::value,
358 "unique_ptr's deleter must be invocable with a pointer");
359 auto& __ptr = _M_t._M_ptr();
360 if (__ptr != nullptr)
361 get_deleter()(std::move(__ptr));
362 __ptr = pointer();
363 }
364
365 // Assignment.
366
367 /** @brief Move assignment operator.
368 *
369 * Invokes the deleter if this object owns a pointer.
370 */
371 unique_ptr& operator=(unique_ptr&&) = default;
372
373 /** @brief Assignment from another type.
374 *
375 * @param __u The object to transfer ownership from, which owns a
376 * convertible pointer to a non-array object.
377 *
378 * Invokes the deleter if this object owns a pointer.
379 */
380 template<typename _Up, typename _Ep>
381 typename enable_if< __and_<
382 __safe_conversion_up<_Up, _Ep>,
383 is_assignable<deleter_type&, _Ep&&>
384 >::value,
385 unique_ptr&>::type
386 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
387 {
388 reset(__u.release());
389 get_deleter() = std::forward<_Ep>(__u.get_deleter());
390 return *this;
391 }
392
393 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
394 unique_ptr&
395 operator=(nullptr_t) noexcept
396 {
397 reset();
398 return *this;
399 }
400
401 // Observers.
402
403 /// Dereference the stored pointer.
404 typename add_lvalue_reference<element_type>::type
405 operator*() const
406 {
407 __glibcxx_assert(get() != pointer());
408 return *get();
409 }
410
411 /// Return the stored pointer.
412 pointer
413 operator->() const noexcept
414 {
415 _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
416 return get();
417 }
418
419 /// Return the stored pointer.
420 pointer
421 get() const noexcept
422 { return _M_t._M_ptr(); }
423
424 /// Return a reference to the stored deleter.
425 deleter_type&
426 get_deleter() noexcept
427 { return _M_t._M_deleter(); }
428
429 /// Return a reference to the stored deleter.
430 const deleter_type&
431 get_deleter() const noexcept
432 { return _M_t._M_deleter(); }
433
434 /// Return @c true if the stored pointer is not null.
435 explicit operator bool() const noexcept
436 { return get() == pointer() ? false : true; }
12
Assuming the condition is false
13
'?' condition is false
14
Returning the value 1, which participates in a condition later
437
438 // Modifiers.
439
440 /// Release ownership of any stored pointer.
441 pointer
442 release() noexcept
443 { return _M_t.release(); }
444
445 /** @brief Replace the stored pointer.
446 *
447 * @param __p The new pointer to store.
448 *
449 * The deleter will be invoked if a pointer is already owned.
450 */
451 void
452 reset(pointer __p = pointer()) noexcept
453 {
454 static_assert(__is_invocable<deleter_type&, pointer>::value,
455 "unique_ptr's deleter must be invocable with a pointer");
456 _M_t.reset(std::move(__p));
457 }
458
459 /// Exchange the pointer and deleter with another object.
460 void
461 swap(unique_ptr& __u) noexcept
462 {
463 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
464 _M_t.swap(__u._M_t);
465 }
466
467 // Disable copy from lvalue.
468 unique_ptr(const unique_ptr&) = delete;
469 unique_ptr& operator=(const unique_ptr&) = delete;
470 };
471
472 /// 20.7.1.3 unique_ptr for array objects with a runtime length
473 // [unique.ptr.runtime]
474 // _GLIBCXX_RESOLVE_LIB_DEFECTS
475 // DR 740 - omit specialization for array objects with a compile time length
476 template<typename _Tp, typename _Dp>
477 class unique_ptr<_Tp[], _Dp>
478 {
479 template <typename _Up>
480 using _DeleterConstraint =
481 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
482
483 __uniq_ptr_data<_Tp, _Dp> _M_t;
484
485 template<typename _Up>
486 using __remove_cv = typename remove_cv<_Up>::type;
487
488 // like is_base_of<_Tp, _Up> but false if unqualified types are the same
489 template<typename _Up>
490 using __is_derived_Tp
491 = __and_< is_base_of<_Tp, _Up>,
492 __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
493
494 public:
495 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
496 using element_type = _Tp;
497 using deleter_type = _Dp;
498
499 // helper template for detecting a safe conversion from another
500 // unique_ptr
501 template<typename _Up, typename _Ep,
502 typename _UPtr = unique_ptr<_Up, _Ep>,
503 typename _UP_pointer = typename _UPtr::pointer,
504 typename _UP_element_type = typename _UPtr::element_type>
505 using __safe_conversion_up = __and_<
506 is_array<_Up>,
507 is_same<pointer, element_type*>,
508 is_same<_UP_pointer, _UP_element_type*>,
509 is_convertible<_UP_element_type(*)[], element_type(*)[]>
510 >;
511
512 // helper template for detecting a safe conversion from a raw pointer
513 template<typename _Up>
514 using __safe_conversion_raw = __and_<
515 __or_<__or_<is_same<_Up, pointer>,
516 is_same<_Up, nullptr_t>>,
517 __and_<is_pointer<_Up>,
518 is_same<pointer, element_type*>,
519 is_convertible<
520 typename remove_pointer<_Up>::type(*)[],
521 element_type(*)[]>
522 >
523 >
524 >;
525
526 // Constructors.
527
528 /// Default constructor, creates a unique_ptr that owns nothing.
529 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
530 constexpr unique_ptr() noexcept
531 : _M_t()
532 { }
533
534 /** Takes ownership of a pointer.
535 *
536 * @param __p A pointer to an array of a type safely convertible
537 * to an array of @c element_type
538 *
539 * The deleter will be value-initialized.
540 */
541 template<typename _Up,
542 typename _Vp = _Dp,
543 typename = _DeleterConstraint<_Vp>,
544 typename = typename enable_if<
545 __safe_conversion_raw<_Up>::value, bool>::type>
546 explicit
547 unique_ptr(_Up __p) noexcept
548 : _M_t(__p)
549 { }
550
551 /** Takes ownership of a pointer.
552 *
553 * @param __p A pointer to an array of a type safely convertible
554 * to an array of @c element_type
555 * @param __d A reference to a deleter.
556 *
557 * The deleter will be initialized with @p __d
558 */
559 template<typename _Up, typename _Del = deleter_type,
560 typename = _Require<__safe_conversion_raw<_Up>,
561 is_copy_constructible<_Del>>>
562 unique_ptr(_Up __p, const deleter_type& __d) noexcept
563 : _M_t(__p, __d) { }
564
565 /** Takes ownership of a pointer.
566 *
567 * @param __p A pointer to an array of a type safely convertible
568 * to an array of @c element_type
569 * @param __d A reference to a deleter.
570 *
571 * The deleter will be initialized with @p std::move(__d)
572 */
573 template<typename _Up, typename _Del = deleter_type,
574 typename = _Require<__safe_conversion_raw<_Up>,
575 is_move_constructible<_Del>>>
576 unique_ptr(_Up __p,
577 __enable_if_t<!is_lvalue_reference<_Del>::value,
578 _Del&&> __d) noexcept
579 : _M_t(std::move(__p), std::move(__d))
580 { }
581
582 template<typename _Up, typename _Del = deleter_type,
583 typename _DelUnref = typename remove_reference<_Del>::type,
584 typename = _Require<__safe_conversion_raw<_Up>>>
585 unique_ptr(_Up,
586 __enable_if_t<is_lvalue_reference<_Del>::value,
587 _DelUnref&&>) = delete;
588
589 /// Move constructor.
590 unique_ptr(unique_ptr&&) = default;
591
592 /// Creates a unique_ptr that owns nothing.
593 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
594 constexpr unique_ptr(nullptr_t) noexcept
595 : _M_t()
596 { }
597
598 template<typename _Up, typename _Ep, typename = _Require<
599 __safe_conversion_up<_Up, _Ep>,
600 typename conditional<is_reference<_Dp>::value,
601 is_same<_Ep, _Dp>,
602 is_convertible<_Ep, _Dp>>::type>>
603 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
604 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
605 { }
606
607 /// Destructor, invokes the deleter if the stored pointer is not null.
608 ~unique_ptr()
609 {
610 auto& __ptr = _M_t._M_ptr();
611 if (__ptr != nullptr)
612 get_deleter()(__ptr);
613 __ptr = pointer();
614 }
615
616 // Assignment.
617
618 /** @brief Move assignment operator.
619 *
620 * Invokes the deleter if this object owns a pointer.
621 */
622 unique_ptr&
623 operator=(unique_ptr&&) = default;
624
625 /** @brief Assignment from another type.
626 *
627 * @param __u The object to transfer ownership from, which owns a
628 * convertible pointer to an array object.
629 *
630 * Invokes the deleter if this object owns a pointer.
631 */
632 template<typename _Up, typename _Ep>
633 typename
634 enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
635 is_assignable<deleter_type&, _Ep&&>
636 >::value,
637 unique_ptr&>::type
638 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
639 {
640 reset(__u.release());
641 get_deleter() = std::forward<_Ep>(__u.get_deleter());
642 return *this;
643 }
644
645 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
646 unique_ptr&
647 operator=(nullptr_t) noexcept
648 {
649 reset();
650 return *this;
651 }
652
653 // Observers.
654
655 /// Access an element of owned array.
656 typename std::add_lvalue_reference<element_type>::type
657 operator[](size_t __i) const
658 {
659 __glibcxx_assert(get() != pointer());
660 return get()[__i];
661 }
662
663 /// Return the stored pointer.
664 pointer
665 get() const noexcept
666 { return _M_t._M_ptr(); }
667
668 /// Return a reference to the stored deleter.
669 deleter_type&
670 get_deleter() noexcept
671 { return _M_t._M_deleter(); }
672
673 /// Return a reference to the stored deleter.
674 const deleter_type&
675 get_deleter() const noexcept
676 { return _M_t._M_deleter(); }
677
678 /// Return @c true if the stored pointer is not null.
679 explicit operator bool() const noexcept
680 { return get() == pointer() ? false : true; }
681
682 // Modifiers.
683
684 /// Release ownership of any stored pointer.
685 pointer
686 release() noexcept
687 { return _M_t.release(); }
688
689 /** @brief Replace the stored pointer.
690 *
691 * @param __p The new pointer to store.
692 *
693 * The deleter will be invoked if a pointer is already owned.
694 */
695 template <typename _Up,
696 typename = _Require<
697 __or_<is_same<_Up, pointer>,
698 __and_<is_same<pointer, element_type*>,
699 is_pointer<_Up>,
700 is_convertible<
701 typename remove_pointer<_Up>::type(*)[],
702 element_type(*)[]
703 >
704 >
705 >
706 >>
707 void
708 reset(_Up __p) noexcept
709 { _M_t.reset(std::move(__p)); }
710
711 void reset(nullptr_t = nullptr) noexcept
712 { reset(pointer()); }
713
714 /// Exchange the pointer and deleter with another object.
715 void
716 swap(unique_ptr& __u) noexcept
717 {
718 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
719 _M_t.swap(__u._M_t);
720 }
721
722 // Disable copy from lvalue.
723 unique_ptr(const unique_ptr&) = delete;
724 unique_ptr& operator=(const unique_ptr&) = delete;
725 };
726
727 /// @relates unique_ptr @{
728
729 /// Swap overload for unique_ptr
730 template<typename _Tp, typename _Dp>
731 inline
732#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
733 // Constrained free swap overload, see p0185r1
734 typename enable_if<__is_swappable<_Dp>::value>::type
735#else
736 void
737#endif
738 swap(unique_ptr<_Tp, _Dp>& __x,
739 unique_ptr<_Tp, _Dp>& __y) noexcept
740 { __x.swap(__y); }
741
742#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
743 template<typename _Tp, typename _Dp>
744 typename enable_if<!__is_swappable<_Dp>::value>::type
745 swap(unique_ptr<_Tp, _Dp>&,
746 unique_ptr<_Tp, _Dp>&) = delete;
747#endif
748
749 /// Equality operator for unique_ptr objects, compares the owned pointers
750 template<typename _Tp, typename _Dp,
751 typename _Up, typename _Ep>
752 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
753 operator==(const unique_ptr<_Tp, _Dp>& __x,
754 const unique_ptr<_Up, _Ep>& __y)
755 { return __x.get() == __y.get(); }
756
757 /// unique_ptr comparison with nullptr
758 template<typename _Tp, typename _Dp>
759 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
760 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
761 { return !__x; }
762
763#ifndef __cpp_lib_three_way_comparison
764 /// unique_ptr comparison with nullptr
765 template<typename _Tp, typename _Dp>
766 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
767 operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
768 { return !__x; }
769
770 /// Inequality operator for unique_ptr objects, compares the owned pointers
771 template<typename _Tp, typename _Dp,
772 typename _Up, typename _Ep>
773 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
774 operator!=(const unique_ptr<_Tp, _Dp>& __x,
775 const unique_ptr<_Up, _Ep>& __y)
776 { return __x.get() != __y.get(); }
777
778 /// unique_ptr comparison with nullptr
779 template<typename _Tp, typename _Dp>
780 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
781 operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
782 { return (bool)__x; }
783
784 /// unique_ptr comparison with nullptr
785 template<typename _Tp, typename _Dp>
786 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
787 operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
788 { return (bool)__x; }
789#endif // three way comparison
790
791 /// Relational operator for unique_ptr objects, compares the owned pointers
792 template<typename _Tp, typename _Dp,
793 typename _Up, typename _Ep>
794 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
795 operator<(const unique_ptr<_Tp, _Dp>& __x,
796 const unique_ptr<_Up, _Ep>& __y)
797 {
798 typedef typename
799 std::common_type<typename unique_ptr<_Tp, _Dp>::pointer,
800 typename unique_ptr<_Up, _Ep>::pointer>::type _CT;
801 return std::less<_CT>()(__x.get(), __y.get());
802 }
803
804 /// unique_ptr comparison with nullptr
805 template<typename _Tp, typename _Dp>
806 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
807 operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
808 {
809 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
810 nullptr);
811 }
812
813 /// unique_ptr comparison with nullptr
814 template<typename _Tp, typename _Dp>
815 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
816 operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
817 {
818 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
819 __x.get());
820 }
821
822 /// Relational operator for unique_ptr objects, compares the owned pointers
823 template<typename _Tp, typename _Dp,
824 typename _Up, typename _Ep>
825 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
826 operator<=(const unique_ptr<_Tp, _Dp>& __x,
827 const unique_ptr<_Up, _Ep>& __y)
828 { return !(__y < __x); }
829
830 /// unique_ptr comparison with nullptr
831 template<typename _Tp, typename _Dp>
832 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
833 operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
834 { return !(nullptr < __x); }
835
836 /// unique_ptr comparison with nullptr
837 template<typename _Tp, typename _Dp>
838 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
839 operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
840 { return !(__x < nullptr); }
841
842 /// Relational operator for unique_ptr objects, compares the owned pointers
843 template<typename _Tp, typename _Dp,
844 typename _Up, typename _Ep>
845 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
846 operator>(const unique_ptr<_Tp, _Dp>& __x,
847 const unique_ptr<_Up, _Ep>& __y)
848 { return (__y < __x); }
849
850 /// unique_ptr comparison with nullptr
851 template<typename _Tp, typename _Dp>
852 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
853 operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
854 {
855 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
856 __x.get());
857 }
858
859 /// unique_ptr comparison with nullptr
860 template<typename _Tp, typename _Dp>
861 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
862 operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
863 {
864 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
865 nullptr);
866 }
867
868 /// Relational operator for unique_ptr objects, compares the owned pointers
869 template<typename _Tp, typename _Dp,
870 typename _Up, typename _Ep>
871 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
872 operator>=(const unique_ptr<_Tp, _Dp>& __x,
873 const unique_ptr<_Up, _Ep>& __y)
874 { return !(__x < __y); }
875
876 /// unique_ptr comparison with nullptr
877 template<typename _Tp, typename _Dp>
878 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
879 operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
880 { return !(__x < nullptr); }
881
882 /// unique_ptr comparison with nullptr
883 template<typename _Tp, typename _Dp>
884 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
885 operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
886 { return !(nullptr < __x); }
887
888#ifdef __cpp_lib_three_way_comparison
889 template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
890 requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
891 typename unique_ptr<_Up, _Ep>::pointer>
892 inline
893 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
894 typename unique_ptr<_Up, _Ep>::pointer>
895 operator<=>(const unique_ptr<_Tp, _Dp>& __x,
896 const unique_ptr<_Up, _Ep>& __y)
897 { return compare_three_way()(__x.get(), __y.get()); }
898
899 template<typename _Tp, typename _Dp>
900 requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
901 inline
902 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
903 operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
904 {
905 using pointer = typename unique_ptr<_Tp, _Dp>::pointer;
906 return compare_three_way()(__x.get(), static_cast<pointer>(nullptr));
907 }
908#endif
909 // @} relates unique_ptr
910
911 /// @cond undocumented
912 template<typename _Up, typename _Ptr = typename _Up::pointer,
913 bool = __poison_hash<_Ptr>::__enable_hash_call>
914 struct __uniq_ptr_hash
915#if ! _GLIBCXX_INLINE_VERSION0
916 : private __poison_hash<_Ptr>
917#endif
918 {
919 size_t
920 operator()(const _Up& __u) const
921 noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>())))
922 { return hash<_Ptr>()(__u.get()); }
923 };
924
925 template<typename _Up, typename _Ptr>
926 struct __uniq_ptr_hash<_Up, _Ptr, false>
927 : private __poison_hash<_Ptr>
928 { };
929 /// @endcond
930
931 /// std::hash specialization for unique_ptr.
932 template<typename _Tp, typename _Dp>
933 struct hash<unique_ptr<_Tp, _Dp>>
934 : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>,
935 public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>>
936 { };
937
938#if __cplusplus201703L >= 201402L
939 /// @relates unique_ptr @{
940#define __cpp_lib_make_unique201304 201304
941
942 /// @cond undocumented
943
944 template<typename _Tp>
945 struct _MakeUniq
946 { typedef unique_ptr<_Tp> __single_object; };
947
948 template<typename _Tp>
949 struct _MakeUniq<_Tp[]>
950 { typedef unique_ptr<_Tp[]> __array; };
951
952 template<typename _Tp, size_t _Bound>
953 struct _MakeUniq<_Tp[_Bound]>
954 { struct __invalid_type { }; };
955
956 /// @endcond
957
958 /// std::make_unique for single objects
959 template<typename _Tp, typename... _Args>
960 inline typename _MakeUniq<_Tp>::__single_object
961 make_unique(_Args&&... __args)
962 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
963
964 /// std::make_unique for arrays of unknown bound
965 template<typename _Tp>
966 inline typename _MakeUniq<_Tp>::__array
967 make_unique(size_t __num)
968 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
969
970 /// Disable std::make_unique for arrays of known bound
971 template<typename _Tp, typename... _Args>
972 inline typename _MakeUniq<_Tp>::__invalid_type
973 make_unique(_Args&&...) = delete;
974 // @} relates unique_ptr
975#endif // C++14
976
977#if __cplusplus201703L > 201703L && __cpp_concepts
978 // _GLIBCXX_RESOLVE_LIB_DEFECTS
979 // 2948. unique_ptr does not define operator<< for stream output
980 /// Stream output operator for unique_ptr
981 template<typename _CharT, typename _Traits, typename _Tp, typename _Dp>
982 inline basic_ostream<_CharT, _Traits>&
983 operator<<(basic_ostream<_CharT, _Traits>& __os,
984 const unique_ptr<_Tp, _Dp>& __p)
985 requires requires { __os << __p.get(); }
986 {
987 __os << __p.get();
988 return __os;
989 }
990#endif // C++20
991
992 // @} group pointer_abstractions
993
994#if __cplusplus201703L >= 201703L
995 namespace __detail::__variant
996 {
997 template<typename> struct _Never_valueless_alt; // see <variant>
998
999 // Provide the strong exception-safety guarantee when emplacing a
1000 // unique_ptr into a variant.
1001 template<typename _Tp, typename _Del>
1002 struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>>
1003 : std::true_type
1004 { };
1005 } // namespace __detail::__variant
1006#endif // C++17
1007
1008_GLIBCXX_END_NAMESPACE_VERSION
1009} // namespace
1010
1011#endif /* _UNIQUE_PTR_H */

/home/maarten/src/libreoffice/core/sw/inc/calbck.hxx

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#ifndef INCLUDED_SW_INC_CALBCK_HXX
21#define INCLUDED_SW_INC_CALBCK_HXX
22
23#include <cassert>
24
25#include <svl/hint.hxx>
26#include <svl/broadcast.hxx>
27#include <svl/poolitem.hxx>
28#include "swdllapi.h"
29#include "ring.hxx"
30#include <type_traits>
31#include <vector>
32#include <memory>
33
34class SwModify;
35class SfxPoolItem;
36
37/*
38 SwModify and SwClient cooperate in propagating attribute changes.
39 If an attribute changes, the change is notified to all dependent
40 formats and other interested objects, e.g. Nodes. The clients will detect
41 if the change affects them. It could be that the changed attribute is
42 overruled in the receiving object so that its change does not become
43 effective or that the receiver is not interested in the particular attribute
44 in general (though probably in other attributes of the SwModify object they
45 are registered in).
46 As SwModify objects are derived from SwClient, they can create a chain of SwClient
47 objects where changes can get propagated through.
48 Each SwClient can be registered at only one SwModify object, while each SwModify
49 object is connected to a list of SwClient objects. If an object derived from SwClient
50 wants to get notifications from more than one SwModify object, it must create additional
51 SwClient objects. The SwDepend class allows to handle their notifications in the same
52 notification callback as it forwards the Modify() calls it receives to a "master"
53 SwClient implementation.
54 The SwIterator class allows to iterate over the SwClient objects registered at an
55 SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
56 to objects of a particular type created a lot of code that misuses SwClient-SwModify
57 relationships that basically should be used only for Modify/Notify callbacks.
58 This is still subject to refactoring.
59 */
60
61namespace sw
62{
63 class ClientIteratorBase;
64 struct LegacyModifyHint final: SfxHint
65 {
66 LegacyModifyHint(const SfxPoolItem* pOld, const SfxPoolItem* pNew) : m_pOld(pOld), m_pNew(pNew) {};
67 sal_uInt16 GetWhich() const { return m_pOld ? m_pOld->Which() : m_pNew ? m_pNew->Which() : 0; };
68 virtual ~LegacyModifyHint() override;
69 const SfxPoolItem* m_pOld;
70 const SfxPoolItem* m_pNew;
71 };
72 struct ModifyChangedHint final: SfxHint
73 {
74 ModifyChangedHint(const SwModify* pNew) : m_pNew(pNew) {};
75 virtual ~ModifyChangedHint() override;
76 const SwModify* m_pNew;
77 };
78 // Observer pattern using svl implementation
79 // use this instead of SwClient/SwModify wherever possible
80 // In writer layout, this might not always be possible,
81 // but for listeners outside of it (e.g. unocore) this should be used.
82 // The only "magic" signal this class issues is a ModifyChangedHint
83 // proclaiming its death. It does NOT however provide a new SwModify for
84 // listeners to switch to like the old SwModify/SwClient did, as that leads
85 // to madness.
86 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) BroadcasterMixin {
87 SvtBroadcaster m_aNotifier;
88 public:
89 BroadcasterMixin() = default;
90 BroadcasterMixin(BroadcasterMixin const &) = default;
91 BroadcasterMixin& operator=(const BroadcasterMixin&)
92 {
93 return *this; // Listeners are never copied or moved.
94 }
95 SvtBroadcaster& GetNotifier() { return m_aNotifier; }
96 };
97 /// refactoring out the same of the more sane SwClient functionality
98 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) WriterListener
99 {
100 friend class ::SwModify;
101 friend class ::sw::ClientIteratorBase;
102 private:
103 WriterListener* m_pLeft;
104 WriterListener* m_pRight; ///< double-linked list of other clients
105
106 WriterListener(WriterListener const&) = delete;
107 WriterListener& operator=(WriterListener const&) = delete;
108
109 protected:
110 WriterListener()
111 : m_pLeft(nullptr), m_pRight(nullptr)
112 {}
113 virtual ~WriterListener() COVERITY_NOEXCEPT_FALSE {}
114 virtual void SwClientNotify( const SwModify&, const SfxHint& rHint) =0;
115 public:
116 bool IsLast() const { return !m_pLeft && !m_pRight; }
117 };
118 enum class IteratorMode { Exact, UnwrapMulti };
119}
120
121// SwClient
122class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwClient : public ::sw::WriterListener
123{
124 // avoids making the details of the linked list and the callback method public
125 friend class SwModify;
126 friend class sw::ClientIteratorBase;
127 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
128
129 SwModify *m_pRegisteredIn; ///< event source
130
131protected:
132 // single argument ctors shall be explicit.
133 inline explicit SwClient( SwModify* pToRegisterIn );
134
135 // write access to pRegisteredIn shall be granted only to the object itself (protected access)
136 SwModify* GetRegisteredInNonConst() const { return m_pRegisteredIn; }
137
138public:
139 SwClient() : m_pRegisteredIn(nullptr) {}
140 SwClient(SwClient&&) noexcept;
141 virtual ~SwClient() override;
142 // callbacks received from SwModify (friend class - so these methods can be private)
143 // should be called only from SwModify the client is registered in
144 // mba: IMHO this method should be pure virtual
145 // DO NOT USE IN NEW CODE! use SwClientNotify instead.
146 virtual void Modify(const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue);
147 // when overriding this, you MUST call SwClient::SwClientModify() in the override!
148 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override;
149
150 // in case an SwModify object is destroyed that itself is registered in another SwModify,
151 // its SwClient objects can decide to get registered to the latter instead by calling this method
152 std::unique_ptr<sw::ModifyChangedHint> CheckRegistration( const SfxPoolItem* pOldValue );
153
154 // controlled access to Modify method
155 // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
156 virtual void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); }
157 void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
158
159 const SwModify* GetRegisteredIn() const { return m_pRegisteredIn; }
160 SwModify* GetRegisteredIn() { return m_pRegisteredIn; }
161 void EndListeningAll();
162 void StartListeningToSameModifyAs(const SwClient&);
163
164
165 // get information about attribute
166 virtual bool GetInfo( SfxPoolItem& ) const { return true; }
167};
168
169
170// SwModify
171
172// class has a doubly linked list for dependencies
173class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwModify: public SwClient
174{
175 friend class sw::ClientIteratorBase;
176 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
177 sw::WriterListener* m_pWriterListeners; // the start of the linked list of clients
178 bool m_bModifyLocked : 1; // don't broadcast changes now
179 bool m_bLockClientList : 1; // may be set when this instance notifies its clients
180 bool m_bInCache : 1;
181 bool m_bInSwFntCache : 1;
182
183 // mba: IMHO this method should be pure virtual
184 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
185 virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) override
186 { NotifyClients( pOld, pNew ); };
187
188 SwModify(SwModify const &) = delete;
189 SwModify &operator =(const SwModify&) = delete;
190public:
191 SwModify()
192 : SwClient(), m_pWriterListeners(nullptr), m_bModifyLocked(false), m_bLockClientList(false), m_bInCache(false), m_bInSwFntCache(false)
193 {}
194
195 // broadcasting: send notifications to all clients
196 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
197 void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
198 // the same, but without setting m_bModifyLocked or checking for any of the flags
199 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
200 void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
201 { CallSwClientNotify( sw::LegacyModifyHint{ pOldValue, pNewValue } ); };
202
203 // a more universal broadcasting mechanism
204 virtual void CallSwClientNotify( const SfxHint& rHint ) const;
205
206 virtual ~SwModify() override;
207
208 void Add(SwClient *pDepend);
209 SwClient* Remove(SwClient *pDepend);
210 bool HasWriterListeners() const { return m_pWriterListeners; }
211
212 // get information about attribute
213 virtual bool GetInfo( SfxPoolItem& ) const override;
214
215 void LockModify() { m_bModifyLocked = true; }
216 void UnlockModify() { m_bModifyLocked = false; }
217 void SetInCache( bool bNew ) { m_bInCache = bNew; }
218 void SetInSwFntCache( bool bNew ) { m_bInSwFntCache = bNew; }
219 void SetInDocDTOR();
220 bool IsModifyLocked() const { return m_bModifyLocked; }
221 bool IsInCache() const { return m_bInCache; }
222 bool IsInSwFntCache() const { return m_bInSwFntCache; }
223
224 void CheckCaching( const sal_uInt16 nWhich );
225 bool HasOnlyOneListener() const { return m_pWriterListeners && m_pWriterListeners->IsLast(); }
226};
227
228template<typename TElementType, typename TSource, sw::IteratorMode eMode> class SwIterator;
229
230namespace sw
231{
232 // this class is part of the migration: it still forwards the "old"
233 // SwModify events and announces them both to the old SwClients still
234 // registered and also to the new SvtListeners.
235 // Still: in the long run the SwClient/SwModify interface should not be
236 // used anymore, in which case a BroadcasterMixin should be enough instead
237 // then.
238 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) BroadcastingModify : public SwModify, public BroadcasterMixin {
239 public:
240 virtual void CallSwClientNotify(const SfxHint& rHint) const override;
241 };
242 // this should be hidden but sadly SwIterator template needs it...
243 class ListenerEntry final : public SwClient
244 {
245 private:
246 template<typename E, typename S, sw::IteratorMode> friend class ::SwIterator;
247 SwClient *m_pToTell;
248
249 public:
250 ListenerEntry(SwClient *const pTellHim, SwModify *const pDepend)
251 : SwClient(pDepend), m_pToTell(pTellHim)
252 {}
253 ListenerEntry(ListenerEntry const &) = delete;
254 ListenerEntry& operator=(ListenerEntry const&) = delete;
255 ListenerEntry(ListenerEntry&& other) noexcept
256 : SwClient(std::move(other))
257 , m_pToTell(other.m_pToTell)
258 { }
259 ListenerEntry& operator=(ListenerEntry&& other) noexcept
260 {
261 m_pToTell = other.m_pToTell;
262 other.GetRegisteredIn()->Add(this);
263 other.EndListeningAll();
264 return *this;
265 }
266
267 /** get Client information */
268 virtual bool GetInfo( SfxPoolItem& rInfo) const override;
269 private:
270 virtual void Modify(const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue) override;
271 virtual void SwClientNotify(const SwModify& rModify, const SfxHint& rHint) override;
272 };
273
274 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) WriterMultiListener final
275 {
276 SwClient& m_rToTell;
277 std::vector<ListenerEntry> m_vDepends;
278 public:
279 WriterMultiListener(SwClient& rToTell);
280 WriterMultiListener& operator=(WriterMultiListener const&) = delete; // MSVC2015 workaround
281 WriterMultiListener(WriterMultiListener const&) = delete; // MSVC2015 workaround
282 ~WriterMultiListener();
283 void StartListening(SwModify* pDepend);
284 void EndListening(SwModify* pDepend);
285 bool IsListeningTo(const SwModify* const pDepend) const;
286 void EndListeningAll();
287 };
288 class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
289 {
290 friend SwClient* SwModify::Remove(SwClient*);
291 friend void SwModify::Add(SwClient*);
292 protected:
293 const SwModify& m_rRoot;
294 // the current object in an iteration
295 WriterListener* m_pCurrent;
296 // in case the current object is already removed, the next object in the list
297 // is marked down to become the current object in the next step
298 // this is necessary because iteration requires access to members of the current object
299 WriterListener* m_pPosition;
300 static SW_DLLPUBLIC__attribute__ ((visibility("default"))) ClientIteratorBase* s_pClientIters;
301
302 ClientIteratorBase( const SwModify& rModify )
303 : m_rRoot(rModify)
304 {
305 MoveTo(s_pClientIters);
21
Calling 'Ring::MoveTo'
32
Returning from 'Ring::MoveTo'
306 s_pClientIters = this;
307 m_pCurrent = m_pPosition = m_rRoot.m_pWriterListeners;
308 }
309 WriterListener* GetLeftOfPos() { return m_pPosition->m_pLeft; }
310 WriterListener* GetRightOfPos() { return m_pPosition->m_pRight; }
311 WriterListener* GoStart()
312 {
313 m_pPosition = m_rRoot.m_pWriterListeners;
314 if(m_pPosition)
315 while( m_pPosition->m_pLeft )
316 m_pPosition = m_pPosition->m_pLeft;
317 m_pCurrent = m_pPosition;
318 return m_pCurrent;
319 }
320 ~ClientIteratorBase() override
321 {
322 assert(s_pClientIters)(static_cast <bool> (s_pClientIters) ? void (0) : __assert_fail
("s_pClientIters", "/home/maarten/src/libreoffice/core/sw/inc/calbck.hxx"
, 322, __extension__ __PRETTY_FUNCTION__))
;
323 if(s_pClientIters == this)
324 s_pClientIters = unique() ? nullptr : GetNextInRing();
325 MoveTo(nullptr);
326 }
327 // return "true" if an object was removed from a client chain in iteration
328 // adding objects to a client chain in iteration is forbidden
329 // SwModify::Add() asserts this
330 bool IsChanged() const { return m_pPosition != m_pCurrent; }
331 // ensures the iterator to point at a current client
332 WriterListener* Sync() { m_pCurrent = m_pPosition; return m_pCurrent; }
333 };
334}
335
336template<typename TElementType, typename TSource,
337 sw::IteratorMode eMode = sw::IteratorMode::Exact> class SwIterator final
338 : private sw::ClientIteratorBase
339{
340 //static_assert(!std::is_base_of<SwPageDesc,TSource>::value, "SwPageDesc as TSource is deprecated.");
341 static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient.");
342 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify.");
343public:
344 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
20
Calling constructor for 'ClientIteratorBase'
33
Returning from constructor for 'ClientIteratorBase'
345 TElementType* First()
346 {
347 GoStart();
348 if(!m_pPosition)
36
Assuming field 'm_pPosition' is non-null, which participates in a condition later
37
Taking false branch
349 return nullptr;
350 m_pCurrent = nullptr;
351 return Next();
38
Returning pointer, which participates in a condition later
352 }
353 TElementType* Next()
354 {
355 if(!IsChanged())
356 m_pPosition = GetRightOfPos();
357 sw::WriterListener *pCurrent(m_pPosition);
358 while (m_pPosition)
359 {
360 if (eMode == sw::IteratorMode::UnwrapMulti)
361 {
362 if (auto const pLE = dynamic_cast<sw::ListenerEntry const*>(m_pPosition))
363 {
364 pCurrent = pLE->m_pToTell;
365 }
366 }
367 if (dynamic_cast<const TElementType *>(pCurrent) == nullptr)
368 {
369 m_pPosition = GetRightOfPos();
370 pCurrent = m_pPosition;
371 }
372 else
373 break;
374 }
375 Sync();
376 return static_cast<TElementType*>(pCurrent);
377 }
378 using sw::ClientIteratorBase::IsChanged;
379};
380
381template< typename TSource > class SwIterator<SwClient, TSource> final : private sw::ClientIteratorBase
382{
383 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify");
384public:
385 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
386 SwClient* First()
387 { return static_cast<SwClient*>(GoStart()); }
388 SwClient* Next()
389 {
390 if(!IsChanged())
391 m_pPosition = GetRightOfPos();
392 return static_cast<SwClient*>(Sync());
393 }
394 using sw::ClientIteratorBase::IsChanged;
395};
396
397SwClient::SwClient( SwModify* pToRegisterIn )
398 : m_pRegisteredIn( nullptr )
399{
400 if(pToRegisterIn)
401 pToRegisterIn->Add(this);
402}
403
404#endif
405
406/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/ring.hxx

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#ifndef INCLUDED_SW_INC_RING_HXX
20#define INCLUDED_SW_INC_RING_HXX
21
22#include <utility>
23#include <sal/types.h>
24#include <iterator>
25#include <type_traits>
26#include <boost/iterator/iterator_facade.hpp>
27#include <boost/intrusive/circular_list_algorithms.hpp>
28
29namespace sw
30{
31 template <typename value_type> class RingContainer;
32 template <typename value_type> class RingIterator;
33 /**
34 * An intrusive container class double linking the contained nodes
35 * @example sw/qa/core/uwriter.cxx
36 */
37 template <typename value_type>
38 class SAL_WARN_UNUSED__attribute__((warn_unused)) Ring
39 {
40 public:
41 typedef typename std::add_const<value_type>::type const_value_type;
42 typedef RingContainer<value_type> ring_container;
43 typedef RingContainer<const_value_type> const_ring_container;
44 virtual ~Ring() COVERITY_NOEXCEPT_FALSE
45 { unlink(); };
46 /** algo::unlink is buggy! don't call it directly! */
47 void unlink()
48 {
49 algo::unlink(this);
23
Calling 'circular_list_algorithms::unlink'
28
Returning from 'circular_list_algorithms::unlink'
50 m_pNext = this; // don't leave pointers to old list behind!
51 m_pPrev = this;
52 }
53 /**
54 * Removes this item from its current ring container and adds it to
55 * another ring container. If the item was not alone in the original
56 * ring container, the other items in the ring will stay in the old
57 * ring container.
58 * Note: the newly created item will be inserted just before item pDestRing.
59 * @param pDestRing the container to add this item to
60 */
61 void MoveTo( value_type* pDestRing );
62 /** @return a stl-like container with begin()/end() for iteration */
63 ring_container GetRingContainer();
64 /** @return a stl-like container with begin()/end() for const iteration */
65 const_ring_container GetRingContainer() const;
66
67 protected:
68 /**
69 * Creates a new item in a ring container all by itself.
70 * Note: Ring instances can newer be outside a container. At most, they
71 * are alone in one.
72 */
73 Ring()
74 : m_pNext(this)
75 , m_pPrev(this)
76 { }
77 /**
78 * Creates a new item and add it to an existing ring container.
79 * Note: the newly created item will be inserted just before item pRing.
80 * @param pRing ring container to add the created item to
81 */
82 Ring( value_type* pRing );
83 /** @return the next item in the ring container */
84 value_type* GetNextInRing()
85 { return static_cast<value_type *>(m_pNext); }
86 /** @return the previous item in the ring container */
87 value_type* GetPrevInRing()
88 { return static_cast<value_type *>(m_pPrev); }
89 /** @return the next item in the ring container */
90 const_value_type* GetNextInRing() const
91 { return static_cast<value_type *>(m_pNext); }
92 /** @return the previous item in the ring container */
93 const_value_type* GetPrevInRing() const
94 { return static_cast<value_type *>(m_pPrev); }
95 /** @return true if and only if this item is alone in its ring */
96 bool unique() const
97 { return algo::unique(static_cast< const_value_type* >(this)); }
98
99 private:
100 /** internal implementation class -- not for external use */
101 struct Ring_node_traits
102 {
103 typedef Ring node;
104 typedef Ring* node_ptr;
105 typedef const Ring* const_node_ptr;
106 static node_ptr get_next(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pNext; };
107 static void set_next(node_ptr n, node_ptr next) { n->m_pNext = next; };
108 static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pPrev; };
109 static void set_previous(node_ptr n, node_ptr previous) { n->m_pPrev = previous; };
110 };
111 friend ring_container;
112 friend const_ring_container;
113 friend typename ring_container::iterator;
114 friend typename ring_container::const_iterator;
115 friend typename const_ring_container::iterator;
116 friend typename const_ring_container::const_iterator;
117 friend class boost::iterator_core_access;
118 typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
119 Ring* m_pNext;
120 Ring* m_pPrev;
121 };
122
123 template <typename value_type>
124 inline Ring<value_type>::Ring( value_type* pObj )
125 : m_pNext(this)
126 , m_pPrev(this)
127 {
128 if( pObj )
129 {
130 algo::link_before(pObj, this);
131 }
132 }
133
134 template <typename value_type>
135 inline void Ring<value_type>::MoveTo(value_type* pDestRing)
136 {
137 value_type* pThis = static_cast< value_type* >(this);
138 unlink();
22
Calling 'Ring::unlink'
29
Returning from 'Ring::unlink'
139 // insert into "new"
140 if (pDestRing)
30
Assuming 'pDestRing' is null
31
Taking false branch
141 {
142 algo::link_before(pDestRing, pThis);
143 }
144 }
145
146 /**
147 * helper class that provides Svalue_typeL-style container iteration to the ring
148 */
149 template <typename value_type>
150 class SAL_WARN_UNUSED__attribute__((warn_unused)) RingContainer final
151 {
152 private:
153 /** the item in the ring where iteration starts */
154 value_type* m_pStart;
155 typedef typename std::remove_const<value_type>::type nonconst_value_type;
156
157 public:
158 RingContainer( value_type* pRing ) : m_pStart(pRing) {};
159 typedef RingIterator<value_type> iterator;
160 typedef RingIterator<const value_type> const_iterator;
161 /**
162 * iterator access
163 * @code
164 * for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
165 * do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
166 * @endcode
167 */
168 iterator begin();
169 iterator end();
170 const_iterator begin() const;
171 const_iterator end() const;
172 /** @return the number of elements in the container */
173 size_t size() const
174 { return std::distance(begin(), end()); }
175 /**
176 * Merges two ring containers. All item from both ring containers will
177 * be in the same ring container in the end.
178 * Note: The items of this ring container will be inserted just before
179 * item pDestRing
180 * @param pDestRing the container to merge this container with
181 */
182 void merge( RingContainer< value_type > aDestRing )
183 {
184 // first check that we aren't merged already, swapping would
185 // actually un-merge in this case!
186 assert(m_pStart->m_pPrev != aDestRing.m_pStart)(static_cast <bool> (m_pStart->m_pPrev != aDestRing.
m_pStart) ? void (0) : __assert_fail ("m_pStart->m_pPrev != aDestRing.m_pStart"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 186, __extension__
__PRETTY_FUNCTION__))
;
187 assert(m_pStart != aDestRing.m_pStart->m_pPrev)(static_cast <bool> (m_pStart != aDestRing.m_pStart->
m_pPrev) ? void (0) : __assert_fail ("m_pStart != aDestRing.m_pStart->m_pPrev"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 187, __extension__
__PRETTY_FUNCTION__))
;
188 std::swap(m_pStart->m_pPrev->m_pNext, aDestRing.m_pStart->m_pPrev->m_pNext);
189 std::swap(m_pStart->m_pPrev, aDestRing.m_pStart->m_pPrev);
190 }
191 };
192
193 template <typename value_type>
194 class RingIterator final : public boost::iterator_facade<
195 RingIterator<value_type>
196 , value_type
197 , boost::forward_traversal_tag
198 >
199 {
200 private:
201 typedef typename std::remove_const<value_type>::type nonconst_value_type;
202 public:
203 RingIterator()
204 : m_pCurrent(nullptr)
205 , m_pStart(nullptr)
206 {}
207 explicit RingIterator(nonconst_value_type* pRing, bool bStart = true)
208 : m_pCurrent(nullptr)
209 , m_pStart(pRing)
210 {
211 if(!bStart)
212 m_pCurrent = m_pStart;
213 }
214
215 private:
216 friend class boost::iterator_core_access;
217 void increment()
218 { m_pCurrent = m_pCurrent ? m_pCurrent->GetNextInRing() : m_pStart->GetNextInRing(); }
219 bool equal(RingIterator const& other) const
220 {
221 // we never want to compare iterators from
222 // different rings or starting points
223 assert(m_pStart == other.m_pStart)(static_cast <bool> (m_pStart == other.m_pStart) ? void
(0) : __assert_fail ("m_pStart == other.m_pStart", "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx"
, 223, __extension__ __PRETTY_FUNCTION__))
;
224 return m_pCurrent == other.m_pCurrent;
225 }
226 value_type& dereference() const
227 { return m_pCurrent ? *m_pCurrent : * m_pStart; }
228 /**
229 * value_type is:
230 * - pointing to the current item in the iteration in general
231 * - nullptr if on the first item (begin())
232 * - m_pStart when beyond the last item (end())
233 */
234 nonconst_value_type* m_pCurrent;
235 /** the first item of the iteration */
236 nonconst_value_type* m_pStart;
237 };
238
239 template <typename value_type>
240 inline typename Ring<value_type>::ring_container Ring<value_type>::GetRingContainer()
241 { return Ring<value_type>::ring_container(static_cast< value_type* >(this)); };
242
243 template <typename value_type>
244 inline typename Ring<value_type>::const_ring_container Ring<value_type>::GetRingContainer() const
245 { return Ring<value_type>::const_ring_container(static_cast< const_value_type* >(this)); };
246
247 template <typename value_type>
248 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::begin()
249 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart)); };
250
251 template <typename value_type>
252 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::end()
253 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
254
255 template <typename value_type>
256 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::begin() const
257 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart)); };
258
259 template <typename value_type>
260 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::end() const
261 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
262}
263#endif
264
265/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost/boost/intrusive/circular_list_algorithms.hpp

1/////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Olaf Krzikalla 2004-2006.
4// (C) Copyright Ion Gaztanaga 2006-2014
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9//
10// See http://www.boost.org/libs/intrusive for documentation.
11//
12/////////////////////////////////////////////////////////////////////////////
13
14#ifndef BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
15#define BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
16
17#include <boost/intrusive/detail/config_begin.hpp>
18#include <boost/intrusive/intrusive_fwd.hpp>
19#include <boost/intrusive/detail/algo_type.hpp>
20#include <boost/core/no_exceptions_support.hpp>
21#include <cstddef>
22
23#if defined(BOOST_HAS_PRAGMA_ONCE)
24# pragma once
25#endif
26
27namespace boost {
28namespace intrusive {
29
30//! circular_list_algorithms provides basic algorithms to manipulate nodes
31//! forming a circular doubly linked list. An empty circular list is formed by a node
32//! whose pointers point to itself.
33//!
34//! circular_list_algorithms is configured with a NodeTraits class, which encapsulates the
35//! information about the node to be manipulated. NodeTraits must support the
36//! following interface:
37//!
38//! <b>Typedefs</b>:
39//!
40//! <tt>node</tt>: The type of the node that forms the circular list
41//!
42//! <tt>node_ptr</tt>: A pointer to a node
43//!
44//! <tt>const_node_ptr</tt>: A pointer to a const node
45//!
46//! <b>Static functions</b>:
47//!
48//! <tt>static node_ptr get_previous(const_node_ptr n);</tt>
49//!
50//! <tt>static void set_previous(node_ptr n, node_ptr prev);</tt>
51//!
52//! <tt>static node_ptr get_next(const_node_ptr n);</tt>
53//!
54//! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
55template<class NodeTraits>
56class circular_list_algorithms
57{
58 public:
59 typedef typename NodeTraits::node node;
60 typedef typename NodeTraits::node_ptr node_ptr;
61 typedef typename NodeTraits::const_node_ptr const_node_ptr;
62 typedef NodeTraits node_traits;
63
64 //! <b>Effects</b>: Constructs an non-used list element, so that
65 //! inited(this_node) == true
66 //!
67 //! <b>Complexity</b>: Constant
68 //!
69 //! <b>Throws</b>: Nothing.
70 BOOST_INTRUSIVE_FORCEINLINEinline static void init(node_ptr this_node)
71 {
72 const node_ptr null_node = node_ptr();
73 NodeTraits::set_next(this_node, null_node);
74 NodeTraits::set_previous(this_node, null_node);
75 }
76
77 //! <b>Effects</b>: Returns true is "this_node" is in a non-used state
78 //! as if it was initialized by the "init" function.
79 //!
80 //! <b>Complexity</b>: Constant
81 //!
82 //! <b>Throws</b>: Nothing.
83 BOOST_INTRUSIVE_FORCEINLINEinline static bool inited(const const_node_ptr &this_node)
84 { return !NodeTraits::get_next(this_node); }
85
86 //! <b>Effects</b>: Constructs an empty list, making this_node the only
87 //! node of the circular list:
88 //! <tt>NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node)
89 //! == this_node</tt>.
90 //!
91 //! <b>Complexity</b>: Constant
92 //!
93 //! <b>Throws</b>: Nothing.
94 BOOST_INTRUSIVE_FORCEINLINEinline static void init_header(node_ptr this_node)
95 {
96 NodeTraits::set_next(this_node, this_node);
97 NodeTraits::set_previous(this_node, this_node);
98 }
99
100
101 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
102 //!
103 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
104 //! <tt>return NodeTraits::get_next(this_node) == this_node</tt>
105 //!
106 //! <b>Complexity</b>: Constant
107 //!
108 //! <b>Throws</b>: Nothing.
109 BOOST_INTRUSIVE_FORCEINLINEinline static bool unique(const const_node_ptr &this_node)
110 {
111 node_ptr next = NodeTraits::get_next(this_node);
112 return !next || next == this_node;
113 }
114
115 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
116 //!
117 //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list
118 //! is empty, returns 1.
119 //!
120 //! <b>Complexity</b>: Linear
121 //!
122 //! <b>Throws</b>: Nothing.
123 static std::size_t count(const const_node_ptr &this_node)
124 {
125 std::size_t result = 0;
126 const_node_ptr p = this_node;
127 do{
128 p = NodeTraits::get_next(p);
129 ++result;
130 }while (p != this_node);
131 return result;
132 }
133
134 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
135 //!
136 //! <b>Effects</b>: Unlinks the node from the circular list.
137 //!
138 //! <b>Complexity</b>: Constant
139 //!
140 //! <b>Throws</b>: Nothing.
141 BOOST_INTRUSIVE_FORCEINLINEinline static node_ptr unlink(node_ptr this_node)
142 {
143 node_ptr next(NodeTraits::get_next(this_node));
144 node_ptr prev(NodeTraits::get_previous(this_node));
145 NodeTraits::set_next(prev, next);
24
Calling 'Ring_node_traits::set_next'
25
Returning from 'Ring_node_traits::set_next'
146 NodeTraits::set_previous(next, prev);
26
Calling 'Ring_node_traits::set_previous'
27
Returning from 'Ring_node_traits::set_previous'
147 return next;
148 }
149
150 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
151 //!
152 //! <b>Effects</b>: Unlinks the node [b, e) from the circular list.
153 //!
154 //! <b>Complexity</b>: Constant
155 //!
156 //! <b>Throws</b>: Nothing.
157 BOOST_INTRUSIVE_FORCEINLINEinline static void unlink(node_ptr b, node_ptr e)
158 {
159 if (b != e) {
160 node_ptr prevb(NodeTraits::get_previous(b));
161 NodeTraits::set_previous(e, prevb);
162 NodeTraits::set_next(prevb, e);
163 }
164 }
165
166 //! <b>Requires</b>: nxt_node must be a node of a circular list.
167 //!
168 //! <b>Effects</b>: Links this_node before nxt_node in the circular list.
169 //!
170 //! <b>Complexity</b>: Constant
171 //!
172 //! <b>Throws</b>: Nothing.
173 BOOST_INTRUSIVE_FORCEINLINEinline static void link_before(node_ptr nxt_node, node_ptr this_node)
174 {
175 node_ptr prev(NodeTraits::get_previous(nxt_node));
176 NodeTraits::set_previous(this_node, prev);
177 NodeTraits::set_next(this_node, nxt_node);
178 //nxt_node might be an alias for prev->next_
179 //so use it before NodeTraits::set_next(prev, ...)
180 //is called and the reference changes its value
181 NodeTraits::set_previous(nxt_node, this_node);
182 NodeTraits::set_next(prev, this_node);
183 }
184
185 //! <b>Requires</b>: prev_node must be a node of a circular list.
186 //!
187 //! <b>Effects</b>: Links this_node after prev_node in the circular list.
188 //!
189 //! <b>Complexity</b>: Constant
190 //!
191 //! <b>Throws</b>: Nothing.
192 BOOST_INTRUSIVE_FORCEINLINEinline static void link_after(node_ptr prev_node, node_ptr this_node)
193 {
194 node_ptr next(NodeTraits::get_next(prev_node));
195 NodeTraits::set_previous(this_node, prev_node);
196 NodeTraits::set_next(this_node, next);
197 //prev_node might be an alias for next->next_
198 //so use it before update it before NodeTraits::set_previous(next, ...)
199 //is called and the reference changes it's value
200 NodeTraits::set_next(prev_node, this_node);
201 NodeTraits::set_previous(next, this_node);
202 }
203
204 //! <b>Requires</b>: this_node and other_node must be nodes inserted
205 //! in circular lists or be empty circular lists.
206 //!
207 //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in
208 //! other_nodes position in the second circular list and the other_node is inserted
209 //! in this_node's position in the first circular list.
210 //!
211 //! <b>Complexity</b>: Constant
212 //!
213 //! <b>Throws</b>: Nothing.
214 static void swap_nodes(node_ptr this_node, node_ptr other_node)
215 {
216 if (other_node == this_node)
217 return;
218 bool this_inited = inited(this_node);
219 bool other_inited = inited(other_node);
220 if(this_inited){
221 init_header(this_node);
222 }
223 if(other_inited){
224 init_header(other_node);
225 }
226
227 node_ptr next_this(NodeTraits::get_next(this_node));
228 node_ptr prev_this(NodeTraits::get_previous(this_node));
229 node_ptr next_other(NodeTraits::get_next(other_node));
230 node_ptr prev_other(NodeTraits::get_previous(other_node));
231 //these first two swaps must happen before the other two
232 swap_prev(next_this, next_other);
233 swap_next(prev_this, prev_other);
234 swap_next(this_node, other_node);
235 swap_prev(this_node, other_node);
236
237 if(this_inited){
238 init(other_node);
239 }
240 if(other_inited){
241 init(this_node);
242 }
243 }
244
245 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
246 //! and p must be a node of a different circular list or may not be an iterator in
247 // [b, e).
248 //!
249 //! <b>Effects</b>: Removes the nodes from [b, e) range from their circular list and inserts
250 //! them before p in p's circular list.
251 //!
252 //! <b>Complexity</b>: Constant
253 //!
254 //! <b>Throws</b>: Nothing.
255 static void transfer(node_ptr p, node_ptr b, node_ptr e)
256 {
257 if (b != e) {
258 node_ptr prev_p(NodeTraits::get_previous(p));
259 node_ptr prev_b(NodeTraits::get_previous(b));
260 node_ptr prev_e(NodeTraits::get_previous(e));
261 NodeTraits::set_next(prev_e, p);
262 NodeTraits::set_previous(p, prev_e);
263 NodeTraits::set_next(prev_b, e);
264 NodeTraits::set_previous(e, prev_b);
265 NodeTraits::set_next(prev_p, b);
266 NodeTraits::set_previous(b, prev_p);
267 }
268 }
269
270 //! <b>Requires</b>: i must a node of a circular list
271 //! and p must be a node of a different circular list.
272 //!
273 //! <b>Effects</b>: Removes the node i from its circular list and inserts
274 //! it before p in p's circular list.
275 //! If p == i or p == NodeTraits::get_next(i), this function is a null operation.
276 //!
277 //! <b>Complexity</b>: Constant
278 //!
279 //! <b>Throws</b>: Nothing.
280 static void transfer(node_ptr p, node_ptr i)
281 {
282 node_ptr n(NodeTraits::get_next(i));
283 if(n != p && i != p){
284 node_ptr prev_p(NodeTraits::get_previous(p));
285 node_ptr prev_i(NodeTraits::get_previous(i));
286 NodeTraits::set_next(prev_p, i);
287 NodeTraits::set_previous(i, prev_p);
288 NodeTraits::set_next(i, p);
289 NodeTraits::set_previous(p, i);
290 NodeTraits::set_previous(n, prev_i);
291 NodeTraits::set_next(prev_i, n);
292
293 }
294 }
295
296 //! <b>Effects</b>: Reverses the order of elements in the list.
297 //!
298 //! <b>Throws</b>: Nothing.
299 //!
300 //! <b>Complexity</b>: This function is linear time.
301 static void reverse(node_ptr p)
302 {
303 node_ptr f(NodeTraits::get_next(p));
304 node_ptr i(NodeTraits::get_next(f)), e(p);
305
306 while(i != e) {
307 node_ptr n = i;
308 i = NodeTraits::get_next(i);
309 transfer(f, n, i);
310 f = n;
311 }
312 }
313
314 //! <b>Effects</b>: Moves the node p n positions towards the end of the list.
315 //!
316 //! <b>Throws</b>: Nothing.
317 //!
318 //! <b>Complexity</b>: Linear to the number of moved positions.
319 static void move_backwards(node_ptr p, std::size_t n)
320 {
321 //Null shift, nothing to do
322 if(!n) return;
323 node_ptr first = NodeTraits::get_next(p);
324 //size() == 0 or 1, nothing to do
325 if(first == NodeTraits::get_previous(p)) return;
326 unlink(p);
327 //Now get the new first node
328 while(n--){
329 first = NodeTraits::get_next(first);
330 }
331 link_before(first, p);
332 }
333
334 //! <b>Effects</b>: Moves the node p n positions towards the beginning of the list.
335 //!
336 //! <b>Throws</b>: Nothing.
337 //!
338 //! <b>Complexity</b>: Linear to the number of moved positions.
339 static void move_forward(node_ptr p, std::size_t n)
340 {
341 //Null shift, nothing to do
342 if(!n) return;
343 node_ptr last = NodeTraits::get_previous(p);
344 //size() == 0 or 1, nothing to do
345 if(last == NodeTraits::get_next(p)) return;
346
347 unlink(p);
348 //Now get the new last node
349 while(n--){
350 last = NodeTraits::get_previous(last);
351 }
352 link_after(last, p);
353 }
354
355 //! <b>Requires</b>: f and l must be in a circular list.
356 //!
357 //! <b>Effects</b>: Returns the number of nodes in the range [f, l).
358 //!
359 //! <b>Complexity</b>: Linear
360 //!
361 //! <b>Throws</b>: Nothing.
362 static std::size_t distance(const const_node_ptr &f, const const_node_ptr &l)
363 {
364 const_node_ptr i(f);
365 std::size_t result = 0;
366 while(i != l){
367 i = NodeTraits::get_next(i);
368 ++result;
369 }
370 return result;
371 }
372
373 struct stable_partition_info
374 {
375 std::size_t num_1st_partition;
376 std::size_t num_2nd_partition;
377 node_ptr beg_2st_partition;
378 };
379
380 template<class Pred>
381 static void stable_partition(node_ptr beg, node_ptr end, Pred pred, stable_partition_info &info)
382 {
383 node_ptr bcur = node_traits::get_previous(beg);
384 node_ptr cur = beg;
385 node_ptr new_f = end;
386
387 std::size_t num1 = 0, num2 = 0;
388 while(cur != end){
389 if(pred(cur)){
390 ++num1;
391 bcur = cur;
392 cur = node_traits::get_next(cur);
393 }
394 else{
395 ++num2;
396 node_ptr last_to_remove = bcur;
397 new_f = cur;
398 bcur = cur;
399 cur = node_traits::get_next(cur);
400 BOOST_TRY{ try{
401 //Main loop
402 while(cur != end){
403 if(pred(cur)){ //Might throw
404 ++num1;
405 //Process current node
406 node_traits::set_next (last_to_remove, cur);
407 node_traits::set_previous(cur, last_to_remove);
408 last_to_remove = cur;
409 node_ptr nxt = node_traits::get_next(cur);
410 node_traits::set_next (bcur, nxt);
411 node_traits::set_previous(nxt, bcur);
412 cur = nxt;
413 }
414 else{
415 ++num2;
416 bcur = cur;
417 cur = node_traits::get_next(cur);
418 }
419 }
420 }
421 BOOST_CATCH(...)catch(...){
422 node_traits::set_next (last_to_remove, new_f);
423 node_traits::set_previous(new_f, last_to_remove);
424 BOOST_RETHROWthrow;;
425 }
426 BOOST_CATCH_END}
427 node_traits::set_next(last_to_remove, new_f);
428 node_traits::set_previous(new_f, last_to_remove);
429 break;
430 }
431 }
432 info.num_1st_partition = num1;
433 info.num_2nd_partition = num2;
434 info.beg_2st_partition = new_f;
435 }
436
437 private:
438 BOOST_INTRUSIVE_FORCEINLINEinline static void swap_prev(node_ptr this_node, node_ptr other_node)
439 {
440 node_ptr temp(NodeTraits::get_previous(this_node));
441 NodeTraits::set_previous(this_node, NodeTraits::get_previous(other_node));
442 NodeTraits::set_previous(other_node, temp);
443 }
444
445 BOOST_INTRUSIVE_FORCEINLINEinline static void swap_next(node_ptr this_node, node_ptr other_node)
446 {
447 node_ptr temp(NodeTraits::get_next(this_node));
448 NodeTraits::set_next(this_node, NodeTraits::get_next(other_node));
449 NodeTraits::set_next(other_node, temp);
450 }
451};
452
453/// @cond
454
455template<class NodeTraits>
456struct get_algo<CircularListAlgorithms, NodeTraits>
457{
458 typedef circular_list_algorithms<NodeTraits> type;
459};
460
461/// @endcond
462
463} //namespace intrusive
464} //namespace boost
465
466#include <boost/intrusive/detail/config_end.hpp>
467
468#endif //BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP