File: | home/maarten/src/libreoffice/core/sw/source/core/txtnode/atrftn.cxx |
Warning: | line 515, column 9 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||||||||
44 | namespace { | ||||||||||
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 | |||||||||||
124 | SwFormatFootnote::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 | |||||||||||
134 | bool 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 | |||||||||||
143 | SwFormatFootnote* 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 | |||||||||||
153 | void 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 | |||||||||||
162 | void 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 | |||||||||||
169 | void SwFormatFootnote::SetEndNote( bool b ) | ||||||||||
170 | { | ||||||||||
171 | if ( b != m_bEndNote ) | ||||||||||
| |||||||||||
172 | { | ||||||||||
173 | if ( GetTextFootnote() ) | ||||||||||
174 | { | ||||||||||
175 | GetTextFootnote()->DelFrames(nullptr); | ||||||||||
176 | } | ||||||||||
177 | m_bEndNote = b; | ||||||||||
178 | } | ||||||||||
179 | } | ||||||||||
180 | |||||||||||
181 | SwFormatFootnote::~SwFormatFootnote() | ||||||||||
182 | { | ||||||||||
183 | } | ||||||||||
184 | |||||||||||
185 | OUString 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 | ||||||||||
213 | OUString 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 | |||||||||||
264 | uno::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 | |||||||||||
277 | SwTextFootnote::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 | |||||||||||
286 | SwTextFootnote::~SwTextFootnote() | ||||||||||
287 | { | ||||||||||
288 | SetStartNode( nullptr ); | ||||||||||
289 | } | ||||||||||
290 | |||||||||||
291 | void 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 | |||||||||||
357 | void 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 | |||||||||||
371 | void 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 | |||||||||||
391 | void 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 | ||||||||||
435 | void 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 | |||||||||||
465 | void 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); | ||||||||||
469 | if ( !m_pTextNode
| ||||||||||
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() ) | ||||||||||
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
| ||||||||||
494 | return; | ||||||||||
495 | |||||||||||
496 | SwNodeIndex aIdx( *m_pStartNode ); | ||||||||||
497 | SwContentNode* pCNd = m_pTextNode->GetNodes().GoNext( &aIdx ); | ||||||||||
498 | if( !pCNd ) | ||||||||||
499 | return; | ||||||||||
500 | |||||||||||
501 | SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pCNd); | ||||||||||
502 | for( SwContentFrame* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() ) | ||||||||||
503 | { | ||||||||||
504 | if( pRoot != pFnd->getRootFrame() && pRoot ) | ||||||||||
505 | continue; | ||||||||||
506 | SwPageFrame* pPage = pFnd->FindPageFrame(); | ||||||||||
507 | |||||||||||
508 | SwFrame *pFrame = pFnd->GetUpper(); | ||||||||||
509 | while ( pFrame && !pFrame->IsFootnoteFrame() ) | ||||||||||
510 | pFrame = pFrame->GetUpper(); | ||||||||||
511 | |||||||||||
512 | SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pFrame); | ||||||||||
513 | while ( pFootnote
| ||||||||||
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); | ||||||||||
| |||||||||||
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. | ||||||||||
534 | void 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. | ||||||||||
555 | void 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 | |||||||||||
569 | void 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: */ |
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 | |
45 | namespace 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; } |
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 */ |
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 | |
34 | class SwModify; |
35 | class 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 | |
61 | namespace 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 |
122 | class 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 | |
131 | protected: |
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 | |
138 | public: |
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 |
173 | class 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; |
190 | public: |
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 | |
228 | template<typename TElementType, typename TSource, sw::IteratorMode eMode> class SwIterator; |
229 | |
230 | namespace 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); |
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 | |
336 | template<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."); |
343 | public: |
344 | SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {} |
345 | TElementType* First() |
346 | { |
347 | GoStart(); |
348 | if(!m_pPosition) |
349 | return nullptr; |
350 | m_pCurrent = nullptr; |
351 | return Next(); |
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 | |
381 | template< 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"); |
384 | public: |
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 | |
397 | SwClient::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: */ |
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 | |
29 | namespace 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); |
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(); |
139 | // insert into "new" |
140 | if (pDestRing) |
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: */ |
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 | |
27 | namespace boost { |
28 | namespace 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> |
55 | template<class NodeTraits> |
56 | class 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); |
146 | NodeTraits::set_previous(next, prev); |
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 | |
455 | template<class NodeTraits> |
456 | struct 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 |