File: | home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx |
Warning: | line 878, column 30 Use of zero-allocated memory |
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 <hintids.hxx> | ||||
21 | #include <osl/diagnose.h> | ||||
22 | #include <unotools/collatorwrapper.hxx> | ||||
23 | #include <unotools/localedatawrapper.hxx> | ||||
24 | #include <comphelper/processfactory.hxx> | ||||
25 | #include <docary.hxx> | ||||
26 | #include <fmtanchr.hxx> | ||||
27 | #include <frmfmt.hxx> | ||||
28 | #include <doc.hxx> | ||||
29 | #include <IDocumentUndoRedo.hxx> | ||||
30 | #include <IDocumentFieldsAccess.hxx> | ||||
31 | #include <IDocumentState.hxx> | ||||
32 | #include <node.hxx> | ||||
33 | #include <pam.hxx> | ||||
34 | #include <ndtxt.hxx> | ||||
35 | #include <swtable.hxx> | ||||
36 | #include <swundo.hxx> | ||||
37 | #include <sortopt.hxx> | ||||
38 | #include <docsort.hxx> | ||||
39 | #include <UndoSort.hxx> | ||||
40 | #include <UndoRedline.hxx> | ||||
41 | #include <hints.hxx> | ||||
42 | #include <tblsel.hxx> | ||||
43 | #include <cellatr.hxx> | ||||
44 | #include <redline.hxx> | ||||
45 | #include <node2lay.hxx> | ||||
46 | #include <frameformats.hxx> | ||||
47 | |||||
48 | #include <set> | ||||
49 | #include <utility> | ||||
50 | |||||
51 | using namespace ::com::sun::star::lang; | ||||
52 | using namespace ::com::sun::star; | ||||
53 | |||||
54 | SwSortOptions* SwSortElement::pOptions = nullptr; | ||||
55 | SwDoc* SwSortElement::pDoc = nullptr; | ||||
56 | const FlatFndBox* SwSortElement::pBox = nullptr; | ||||
57 | CollatorWrapper* SwSortElement::pSortCollator = nullptr; | ||||
58 | lang::Locale* SwSortElement::pLocale = nullptr; | ||||
59 | OUString* SwSortElement::pLastAlgorithm = nullptr; | ||||
60 | LocaleDataWrapper* SwSortElement::pLclData = nullptr; | ||||
61 | |||||
62 | // List of all sorted elements | ||||
63 | |||||
64 | /// Construct a SortElement for the Sort | ||||
65 | void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt, | ||||
66 | FlatFndBox const * pFltBx ) | ||||
67 | { | ||||
68 | OSL_ENSURE( !pDoc && !pOptions && !pBox, "Who forgot to call Finit?" )do { if (true && (!(!pDoc && !pOptions && !pBox))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "68" ": "), "%s", "Who forgot to call Finit?"); } } while (false); | ||||
69 | pDoc = pD; | ||||
70 | pOptions = new SwSortOptions( rOpt ); | ||||
71 | pBox = pFltBx; | ||||
72 | |||||
73 | LanguageType nLang = rOpt.nLanguage; | ||||
74 | if ( nLang.anyOf( | ||||
75 | LANGUAGE_NONELanguageType(0x00FF), | ||||
76 | LANGUAGE_DONTKNOWLanguageType(0x03FF))) | ||||
77 | nLang = GetAppLanguage(); | ||||
78 | pLocale = new lang::Locale( LanguageTag::convertToLocale( nLang ) ); | ||||
79 | |||||
80 | pSortCollator = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); | ||||
81 | } | ||||
82 | |||||
83 | void SwSortElement::Finit() | ||||
84 | { | ||||
85 | delete pOptions; | ||||
86 | pOptions = nullptr; | ||||
87 | delete pLocale; | ||||
88 | pLocale = nullptr; | ||||
89 | delete pLastAlgorithm; | ||||
90 | pLastAlgorithm = nullptr; | ||||
91 | delete pSortCollator; | ||||
92 | pSortCollator = nullptr; | ||||
93 | delete pLclData; | ||||
94 | pLclData = nullptr; | ||||
95 | pDoc = nullptr; | ||||
96 | pBox = nullptr; | ||||
97 | } | ||||
98 | |||||
99 | SwSortElement::~SwSortElement() | ||||
100 | { | ||||
101 | } | ||||
102 | |||||
103 | double SwSortElement::StrToDouble( const OUString& rStr ) | ||||
104 | { | ||||
105 | if( !pLclData ) | ||||
106 | pLclData = new LocaleDataWrapper( LanguageTag( *pLocale )); | ||||
107 | |||||
108 | rtl_math_ConversionStatus eStatus; | ||||
109 | sal_Int32 nEnd; | ||||
110 | double nRet = pLclData->stringToDouble( rStr, true, &eStatus, &nEnd ); | ||||
111 | |||||
112 | if( rtl_math_ConversionStatus_Ok != eStatus || nEnd == 0 ) | ||||
113 | nRet = 0.0; | ||||
114 | return nRet; | ||||
115 | } | ||||
116 | |||||
117 | int SwSortElement::keycompare(const SwSortElement& rCmp, sal_uInt16 nKey) const | ||||
118 | { | ||||
119 | int nCmp = 0; | ||||
120 | // The actual comparison | ||||
121 | const SwSortElement *pOrig, *pCmp; | ||||
122 | |||||
123 | const SwSortKey* pSrtKey = pOptions->aKeys[ nKey ].get(); | ||||
124 | if( pSrtKey->eSortOrder == SwSortOrder::Ascending ) | ||||
125 | { | ||||
126 | pOrig = this; | ||||
127 | pCmp = &rCmp; | ||||
128 | } | ||||
129 | else | ||||
130 | { | ||||
131 | pOrig = &rCmp; | ||||
132 | pCmp = this; | ||||
133 | } | ||||
134 | |||||
135 | if( pSrtKey->bIsNumeric ) | ||||
136 | { | ||||
137 | double n1 = pOrig->GetValue( nKey ); | ||||
138 | double n2 = pCmp->GetValue( nKey ); | ||||
139 | |||||
140 | nCmp = n1 < n2 ? -1 : n1 == n2 ? 0 : 1; | ||||
141 | } | ||||
142 | else | ||||
143 | { | ||||
144 | if( !pLastAlgorithm || *pLastAlgorithm != pSrtKey->sSortType ) | ||||
145 | { | ||||
146 | if( pLastAlgorithm ) | ||||
147 | *pLastAlgorithm = pSrtKey->sSortType; | ||||
148 | else | ||||
149 | pLastAlgorithm = new OUString( pSrtKey->sSortType ); | ||||
150 | pSortCollator->loadCollatorAlgorithm( *pLastAlgorithm, | ||||
151 | *pLocale, | ||||
152 | pOptions->bIgnoreCase ? SW_COLLATOR_IGNORES( css::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ) : 0 ); | ||||
153 | } | ||||
154 | |||||
155 | nCmp = pSortCollator->compareString( | ||||
156 | pOrig->GetKey( nKey ), pCmp->GetKey( nKey )); | ||||
157 | } | ||||
158 | return nCmp; | ||||
159 | } | ||||
160 | |||||
161 | bool SwSortElement::operator<(const SwSortElement& rCmp) const | ||||
162 | { | ||||
163 | // The actual comparison | ||||
164 | for(size_t nKey = 0; nKey < pOptions->aKeys.size(); ++nKey) | ||||
165 | { | ||||
166 | int nCmp = keycompare(rCmp, nKey); | ||||
167 | |||||
168 | if (nCmp == 0) | ||||
169 | continue; | ||||
170 | |||||
171 | return nCmp < 0; | ||||
172 | } | ||||
173 | |||||
174 | return false; | ||||
175 | } | ||||
176 | |||||
177 | double SwSortElement::GetValue( sal_uInt16 nKey ) const | ||||
178 | { | ||||
179 | return StrToDouble( GetKey( nKey )); | ||||
180 | } | ||||
181 | |||||
182 | /// SortingElement for Text | ||||
183 | SwSortTextElement::SwSortTextElement(const SwNodeIndex& rPos) | ||||
184 | : nOrg(rPos.GetIndex()), aPos(rPos) | ||||
185 | { | ||||
186 | } | ||||
187 | |||||
188 | OUString SwSortTextElement::GetKey(sal_uInt16 nId) const | ||||
189 | { | ||||
190 | SwTextNode* pTextNd = aPos.GetNode().GetTextNode(); | ||||
191 | if( !pTextNd ) | ||||
192 | return OUString(); | ||||
193 | |||||
194 | // for TextNodes | ||||
195 | const OUString& rStr = pTextNd->GetText(); | ||||
196 | |||||
197 | sal_Unicode nDeli = pOptions->cDeli; | ||||
198 | sal_uInt16 nDCount = pOptions->aKeys[nId]->nColumnId, i = 1; | ||||
199 | sal_Int32 nStart = 0; | ||||
200 | |||||
201 | // Find the delimiter | ||||
202 | while( nStart != -1 && i < nDCount) | ||||
203 | { | ||||
204 | nStart = rStr.indexOf( nDeli, nStart ); | ||||
205 | if( -1 != nStart ) | ||||
206 | { | ||||
207 | nStart++; | ||||
208 | i++; | ||||
209 | } | ||||
210 | } | ||||
211 | |||||
212 | // Found next delimiter or end of String | ||||
213 | // and copy | ||||
214 | sal_Int32 nEnd = rStr.indexOf( nDeli, nStart+1 ); | ||||
215 | if (nEnd == -1) | ||||
216 | return rStr.copy( nStart ); | ||||
217 | return rStr.copy( nStart, nEnd-nStart ); | ||||
218 | } | ||||
219 | |||||
220 | /// SortingElement for Tables | ||||
221 | SwSortBoxElement::SwSortBoxElement( sal_uInt16 nRC ) | ||||
222 | : nRow( nRC ) | ||||
223 | { | ||||
224 | } | ||||
225 | |||||
226 | /// Get Key for a cell | ||||
227 | OUString SwSortBoxElement::GetKey(sal_uInt16 nKey) const | ||||
228 | { | ||||
229 | const FndBox_* pFndBox; | ||||
230 | sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1; | ||||
231 | |||||
232 | if( SwSortDirection::Rows == pOptions->eDirection ) | ||||
233 | pFndBox = pBox->GetBox(nCol, nRow); // Sort rows | ||||
234 | else | ||||
235 | pFndBox = pBox->GetBox(nRow, nCol); // Sort columns | ||||
236 | |||||
237 | // Extract the Text | ||||
238 | OUStringBuffer aRetStr; | ||||
239 | if( pFndBox ) | ||||
240 | { // Get StartNode and skip it | ||||
241 | const SwTableBox* pMyBox = pFndBox->GetBox(); | ||||
242 | OSL_ENSURE(pMyBox, "No atomic Box")do { if (true && (!(pMyBox))) { sal_detail_logFormat( (SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "242" ": "), "%s", "No atomic Box"); } } while (false); | ||||
243 | |||||
244 | if( pMyBox->GetSttNd() ) | ||||
245 | { | ||||
246 | // Iterate over all the Box's TextNodes | ||||
247 | const SwNode *pNd = nullptr, *pEndNd = pMyBox->GetSttNd()->EndOfSectionNode(); | ||||
248 | for( sal_uLong nIdx = pMyBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx ) | ||||
249 | { | ||||
250 | pNd = pDoc->GetNodes()[ nIdx ]; | ||||
251 | if( pNd->IsTextNode() ) | ||||
252 | aRetStr.append(pNd->GetTextNode()->GetText()); | ||||
253 | } | ||||
254 | } | ||||
255 | } | ||||
256 | return aRetStr.makeStringAndClear(); | ||||
257 | } | ||||
258 | |||||
259 | double SwSortBoxElement::GetValue( sal_uInt16 nKey ) const | ||||
260 | { | ||||
261 | const FndBox_* pFndBox; | ||||
262 | sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1; | ||||
263 | |||||
264 | if( SwSortDirection::Rows == pOptions->eDirection ) | ||||
265 | pFndBox = pBox->GetBox(nCol, nRow); // Sort rows | ||||
266 | else | ||||
267 | pFndBox = pBox->GetBox(nRow, nCol); // Sort columns | ||||
268 | |||||
269 | double nVal; | ||||
270 | if( pFndBox ) | ||||
271 | { | ||||
272 | const SwFormat *pFormat = pFndBox->GetBox()->GetFrameFormat(); | ||||
273 | if (pDoc->GetNumberFormatter()->IsTextFormat( pFormat->GetTableBoxNumFormat().GetValue())) | ||||
274 | nVal = SwSortElement::GetValue( nKey ); | ||||
275 | else | ||||
276 | nVal = pFormat->GetTableBoxValue().GetValue(); | ||||
277 | } | ||||
278 | else | ||||
279 | nVal = 0; | ||||
280 | |||||
281 | return nVal; | ||||
282 | } | ||||
283 | |||||
284 | /// Sort Text in the Document | ||||
285 | bool SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt) | ||||
286 | { | ||||
287 | // Check if Frame is in the Text | ||||
288 | const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End(); | ||||
289 | |||||
290 | // Set index to the Selection's start | ||||
291 | for ( const auto *pFormat : *GetSpzFrameFormats() ) | ||||
292 | { | ||||
293 | SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor(); | ||||
294 | SwPosition const*const pAPos = pAnchor->GetContentAnchor(); | ||||
295 | |||||
296 | if (pAPos && (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) && | ||||
297 | pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) | ||||
298 | return false; | ||||
299 | } | ||||
300 | |||||
301 | // Check if only TextNodes are within the Selection | ||||
302 | { | ||||
303 | sal_uLong nStart = pStart->nNode.GetIndex(), | ||||
304 | nEnd = pEnd->nNode.GetIndex(); | ||||
305 | while( nStart <= nEnd ) | ||||
306 | // Iterate over a selected range | ||||
307 | if( !GetNodes()[ nStart++ ]->IsTextNode() ) | ||||
308 | return false; | ||||
309 | } | ||||
310 | |||||
311 | bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); | ||||
312 | if( bUndo ) | ||||
313 | { | ||||
314 | GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); | ||||
315 | } | ||||
316 | |||||
317 | SwPaM* pRedlPam = nullptr; | ||||
318 | SwUndoRedlineSort* pRedlUndo = nullptr; | ||||
319 | SwUndoSort* pUndoSort = nullptr; | ||||
320 | |||||
321 | // To-Do - add 'SwExtraRedlineTable' also ? | ||||
322 | if( getIDocumentRedlineAccess().IsRedlineOn() || (!getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() )) | ||||
323 | { | ||||
324 | pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 ); | ||||
325 | SwContentNode* pCNd = pRedlPam->GetContentNode( false ); | ||||
326 | if( pCNd ) | ||||
327 | pRedlPam->GetMark()->nContent = pCNd->Len(); | ||||
328 | |||||
329 | if( getIDocumentRedlineAccess().IsRedlineOn() && !IDocumentRedlineAccess::IsShowOriginal( getIDocumentRedlineAccess().GetRedlineFlags() ) ) | ||||
330 | { | ||||
331 | if( bUndo ) | ||||
332 | { | ||||
333 | pRedlUndo = new SwUndoRedlineSort( *pRedlPam,rOpt ); | ||||
334 | GetIDocumentUndoRedo().DoUndo(false); | ||||
335 | } | ||||
336 | // First copy the range | ||||
337 | SwNodeIndex aEndIdx( pEnd->nNode, 1 ); | ||||
338 | SwNodeRange aRg( pStart->nNode, aEndIdx ); | ||||
339 | GetNodes().Copy_( aRg, aEndIdx ); | ||||
340 | |||||
341 | // range is new from pEnd->nNode+1 to aEndIdx | ||||
342 | getIDocumentRedlineAccess().DeleteRedline( *pRedlPam, true, RedlineType::Any ); | ||||
343 | |||||
344 | pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 ); | ||||
345 | pCNd = pRedlPam->GetContentNode( false ); | ||||
346 | pRedlPam->GetMark()->nContent.Assign( pCNd, 0 ); | ||||
347 | |||||
348 | pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() ); | ||||
349 | pCNd = pRedlPam->GetContentNode(); | ||||
350 | sal_Int32 nCLen = 0; | ||||
351 | if( !pCNd ) | ||||
352 | { | ||||
353 | pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetContentNode(); | ||||
354 | if( pCNd ) | ||||
355 | { | ||||
356 | nCLen = pCNd->Len(); | ||||
357 | pRedlPam->GetPoint()->nNode.Assign( *pCNd ); | ||||
358 | } | ||||
359 | } | ||||
360 | pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen ); | ||||
361 | |||||
362 | if( pRedlUndo ) | ||||
363 | pRedlUndo->SetValues( rPaM ); | ||||
364 | } | ||||
365 | else | ||||
366 | { | ||||
367 | getIDocumentRedlineAccess().DeleteRedline( *pRedlPam, true, RedlineType::Any ); | ||||
368 | delete pRedlPam; | ||||
369 | pRedlPam = nullptr; | ||||
370 | } | ||||
371 | } | ||||
372 | |||||
373 | SwNodeIndex aStart(pStart->nNode); | ||||
374 | SwSortElement::Init( this, rOpt ); | ||||
375 | std::multiset<SwSortTextElement> aSortSet; | ||||
376 | while( aStart <= pEnd->nNode ) | ||||
377 | { | ||||
378 | // Iterate over a selected range | ||||
379 | aSortSet.insert(SwSortTextElement(aStart)); | ||||
380 | ++aStart; | ||||
381 | } | ||||
382 | |||||
383 | // Now comes the tricky part: Move Nodes (and always keep Undo in mind) | ||||
384 | sal_uLong nBeg = pStart->nNode.GetIndex(); | ||||
385 | SwNodeRange aRg( aStart, aStart ); | ||||
386 | |||||
387 | if( bUndo && !pRedlUndo ) | ||||
388 | { | ||||
389 | pUndoSort = new SwUndoSort(rPaM, rOpt); | ||||
390 | GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoSort)); | ||||
391 | } | ||||
392 | |||||
393 | GetIDocumentUndoRedo().DoUndo(false); | ||||
394 | |||||
395 | size_t n = 0; | ||||
396 | for (const auto& rElem : aSortSet) | ||||
397 | { | ||||
398 | aStart = nBeg + n; | ||||
399 | aRg.aStart = rElem.aPos.GetIndex(); | ||||
400 | aRg.aEnd = aRg.aStart.GetIndex() + 1; | ||||
401 | |||||
402 | // Move Nodes | ||||
403 | getIDocumentContentOperations().MoveNodeRange( aRg, aStart, | ||||
404 | SwMoveFlags::DEFAULT ); | ||||
405 | |||||
406 | // Insert Move in Undo | ||||
407 | if(pUndoSort) | ||||
408 | { | ||||
409 | pUndoSort->Insert(rElem.nOrg, nBeg + n); | ||||
410 | } | ||||
411 | ++n; | ||||
412 | } | ||||
413 | // Delete all elements from the SortArray | ||||
414 | aSortSet.clear(); | ||||
415 | SwSortElement::Finit(); | ||||
416 | |||||
417 | if( pRedlPam ) | ||||
418 | { | ||||
419 | if( pRedlUndo ) | ||||
420 | { | ||||
421 | pRedlUndo->SetSaveRange( *pRedlPam ); | ||||
422 | // UGLY: temp. enable Undo | ||||
423 | GetIDocumentUndoRedo().DoUndo(true); | ||||
424 | GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pRedlUndo) ); | ||||
425 | GetIDocumentUndoRedo().DoUndo(false); | ||||
426 | } | ||||
427 | |||||
428 | // nBeg is start of sorted range | ||||
429 | SwNodeIndex aSttIdx( GetNodes(), nBeg ); | ||||
430 | |||||
431 | // the copied range is deleted | ||||
432 | SwRangeRedline *const pDeleteRedline( | ||||
433 | new SwRangeRedline( RedlineType::Delete, *pRedlPam )); | ||||
434 | |||||
435 | // pRedlPam points to nodes that may be deleted (hidden) by | ||||
436 | // AppendRedline, so adjust it beforehand to prevent ASSERT | ||||
437 | pRedlPam->GetPoint()->nNode = aSttIdx; | ||||
438 | SwContentNode* pCNd = aSttIdx.GetNode().GetContentNode(); | ||||
439 | pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 ); | ||||
440 | |||||
441 | getIDocumentRedlineAccess().AppendRedline(pDeleteRedline, true); | ||||
442 | |||||
443 | // the sorted range is inserted | ||||
444 | getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, *pRedlPam ), true); | ||||
445 | |||||
446 | if( pRedlUndo ) | ||||
447 | { | ||||
448 | SwNodeIndex aInsEndIdx( pRedlPam->GetMark()->nNode, -1 ); | ||||
449 | pRedlPam->GetMark()->nNode = aInsEndIdx; | ||||
450 | SwContentNode *const pPrevNode = | ||||
451 | pRedlPam->GetMark()->nNode.GetNode().GetContentNode(); | ||||
452 | pRedlPam->GetMark()->nContent.Assign( pPrevNode, pPrevNode->Len() ); | ||||
453 | |||||
454 | pRedlUndo->SetValues( *pRedlPam ); | ||||
455 | } | ||||
456 | |||||
457 | delete pRedlPam; | ||||
458 | pRedlPam = nullptr; | ||||
459 | } | ||||
460 | GetIDocumentUndoRedo().DoUndo( bUndo ); | ||||
461 | if( bUndo ) | ||||
462 | { | ||||
463 | GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); | ||||
464 | } | ||||
465 | |||||
466 | return true; | ||||
467 | } | ||||
468 | |||||
469 | /// Sort Table in the Document | ||||
470 | bool SwDoc::SortTable(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt) | ||||
471 | { | ||||
472 | // Via SwDoc for Undo! | ||||
473 | OSL_ENSURE( !rBoxes.empty(), "no valid Box list" )do { if (true && (!(!rBoxes.empty()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "473" ": "), "%s", "no valid Box list"); } } while (false ); | ||||
| |||||
474 | SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode()); | ||||
475 | if( !pTableNd ) | ||||
476 | return false; | ||||
477 | |||||
478 | // We begin sorting | ||||
479 | // Find all Boxes/Lines | ||||
480 | FndBox_ aFndBox( nullptr, nullptr ); | ||||
481 | { | ||||
482 | FndPara aPara( rBoxes, &aFndBox ); | ||||
483 | ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara ); | ||||
484 | } | ||||
485 | |||||
486 | if(aFndBox.GetLines().empty()) | ||||
487 | return false; | ||||
488 | |||||
489 | if( !getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() ) | ||||
490 | getIDocumentRedlineAccess().DeleteRedline( *pTableNd, true, RedlineType::Any ); | ||||
491 | |||||
492 | FndLines_t::size_type nStart = 0; | ||||
493 | if( pTableNd->GetTable().GetRowsToRepeat() > 0 && rOpt.eDirection == SwSortDirection::Rows ) | ||||
494 | { | ||||
495 | // Uppermost selected Cell | ||||
496 | FndLines_t& rLines = aFndBox.GetLines(); | ||||
497 | |||||
498 | while( nStart < rLines.size() ) | ||||
499 | { | ||||
500 | // Respect Split Merge nesting, | ||||
501 | // extract the upper most | ||||
502 | SwTableLine* pLine = rLines[nStart]->GetLine(); | ||||
503 | while ( pLine->GetUpper() ) | ||||
504 | pLine = pLine->GetUpper()->GetUpper(); | ||||
505 | |||||
506 | if( pTableNd->GetTable().IsHeadline( *pLine ) ) | ||||
507 | nStart++; | ||||
508 | else | ||||
509 | break; | ||||
510 | } | ||||
511 | // Are all selected in the HeaderLine? -> no Offset | ||||
512 | if( nStart == rLines.size() ) | ||||
513 | nStart = 0; | ||||
514 | } | ||||
515 | |||||
516 | // Switch to relative Formulas | ||||
517 | SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() ); | ||||
518 | aMsgHint.m_eFlags = TBL_RELBOXNAME; | ||||
519 | getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint ); | ||||
520 | |||||
521 | // Table as a flat array structure | ||||
522 | FlatFndBox aFlatBox(this, aFndBox); | ||||
523 | |||||
524 | if(!aFlatBox.IsSymmetric()) | ||||
525 | return false; | ||||
526 | |||||
527 | // Delete HTML layout | ||||
528 | pTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); | ||||
529 | |||||
530 | // #i37739# A simple 'MakeFrames' after the node sorting | ||||
531 | // does not work if the table is inside a frame and has no prev/next. | ||||
532 | SwNode2LayoutSaveUpperFrames aNode2Layout(*pTableNd); | ||||
533 | |||||
534 | // Delete the Table's Frames | ||||
535 | pTableNd->DelFrames(); | ||||
536 | // ? TL_CHART2: ? | ||||
537 | |||||
538 | SwUndoSort* pUndoSort = nullptr; | ||||
539 | if (GetIDocumentUndoRedo().DoesUndo()) | ||||
540 | { | ||||
541 | pUndoSort = new SwUndoSort( rBoxes[0]->GetSttIdx(), | ||||
542 | rBoxes.back()->GetSttIdx(), | ||||
543 | *pTableNd, rOpt, aFlatBox.HasItemSets() ); | ||||
544 | GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoSort)); | ||||
545 | } | ||||
546 | ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); | ||||
547 | |||||
548 | // Insert KeyElements | ||||
549 | sal_uInt16 nCount = (rOpt.eDirection == SwSortDirection::Rows) ? | ||||
550 | aFlatBox.GetRows() : aFlatBox.GetCols(); | ||||
551 | |||||
552 | // Sort SortList by Key | ||||
553 | SwSortElement::Init( this, rOpt, &aFlatBox ); | ||||
554 | std::multiset<SwSortBoxElement> aSortList; | ||||
555 | |||||
556 | // When sorting, do not include the first row if the HeaderLine is repeated | ||||
557 | for( sal_uInt16 i = static_cast<sal_uInt16>(nStart); i < nCount; ++i) | ||||
558 | { | ||||
559 | aSortList.insert(SwSortBoxElement(i)); | ||||
560 | } | ||||
561 | |||||
562 | // Move after Sorting | ||||
563 | SwMovedBoxes aMovedList; | ||||
564 | sal_uInt16 i = 0; | ||||
565 | for (const auto& rElem : aSortList) | ||||
566 | { | ||||
567 | if(rOpt.eDirection == SwSortDirection::Rows) | ||||
568 | { | ||||
569 | MoveRow(this, aFlatBox, rElem.nRow, i+nStart, aMovedList, pUndoSort); | ||||
570 | } | ||||
571 | else | ||||
572 | { | ||||
573 | MoveCol(this, aFlatBox, rElem.nRow, i+nStart, aMovedList, pUndoSort); | ||||
574 | } | ||||
575 | ++i; | ||||
576 | } | ||||
577 | |||||
578 | // Restore table frames: | ||||
579 | // #i37739# A simple 'MakeFrames' after the node sorting | ||||
580 | // does not work if the table is inside a frame and has no prev/next. | ||||
581 | const sal_uLong nIdx = pTableNd->GetIndex(); | ||||
582 | aNode2Layout.RestoreUpperFrames( GetNodes(), nIdx, nIdx + 1 ); | ||||
583 | |||||
584 | // TL_CHART2: need to inform chart of probably changed cell names | ||||
585 | UpdateCharts( pTableNd->GetTable().GetFrameFormat()->GetName() ); | ||||
586 | |||||
587 | // Delete all Elements in the SortArray | ||||
588 | aSortList.clear(); | ||||
589 | SwSortElement::Finit(); | ||||
590 | |||||
591 | getIDocumentState().SetModified(); | ||||
592 | return true; | ||||
593 | } | ||||
594 | |||||
595 | /// Move a row | ||||
596 | void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT, | ||||
597 | SwMovedBoxes& rMovedList, SwUndoSort* pUD) | ||||
598 | { | ||||
599 | for( sal_uInt16 i=0; i < rBox.GetCols(); ++i ) | ||||
600 | { // Get old cell position and remember it | ||||
601 | const FndBox_* pSource = rBox.GetBox(i, nS); | ||||
602 | |||||
603 | // new cell position | ||||
604 | const FndBox_* pTarget = rBox.GetBox(i, nT); | ||||
605 | |||||
606 | const SwTableBox* pT = pTarget->GetBox(); | ||||
607 | const SwTableBox* pS = pSource->GetBox(); | ||||
608 | |||||
609 | bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX(32767 *2 +1); | ||||
610 | |||||
611 | // and move it | ||||
612 | MoveCell(pDoc, pS, pT, bMoved, pUD); | ||||
613 | |||||
614 | rMovedList.push_back(pS); | ||||
615 | |||||
616 | if( pS != pT ) | ||||
617 | { | ||||
618 | SwFrameFormat* pTFormat = pT->GetFrameFormat(); | ||||
619 | const SfxItemSet* pSSet = rBox.GetItemSet( i, nS ); | ||||
620 | |||||
621 | if( pSSet || | ||||
622 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMAT ) || | ||||
623 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMULA ) || | ||||
624 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_VALUE ) ) | ||||
625 | { | ||||
626 | pTFormat = const_cast<SwTableBox*>(pT)->ClaimFrameFormat(); | ||||
627 | pTFormat->LockModify(); | ||||
628 | if( pTFormat->ResetFormatAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) | ||||
629 | pTFormat->ResetFormatAttr( RES_VERT_ORIENT ); | ||||
630 | |||||
631 | if( pSSet ) | ||||
632 | pTFormat->SetFormatAttr( *pSSet ); | ||||
633 | pTFormat->UnlockModify(); | ||||
634 | } | ||||
635 | } | ||||
636 | } | ||||
637 | } | ||||
638 | |||||
639 | /// Move a column | ||||
640 | void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT, | ||||
641 | SwMovedBoxes& rMovedList, SwUndoSort* pUD) | ||||
642 | { | ||||
643 | for(sal_uInt16 i=0; i < rBox.GetRows(); ++i) | ||||
644 | { // Get old cell position and remember it | ||||
645 | const FndBox_* pSource = rBox.GetBox(nS, i); | ||||
646 | |||||
647 | // new cell position | ||||
648 | const FndBox_* pTarget = rBox.GetBox(nT, i); | ||||
649 | |||||
650 | // and move it | ||||
651 | const SwTableBox* pT = pTarget->GetBox(); | ||||
652 | const SwTableBox* pS = pSource->GetBox(); | ||||
653 | |||||
654 | // and move it | ||||
655 | bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX(32767 *2 +1); | ||||
656 | MoveCell(pDoc, pS, pT, bMoved, pUD); | ||||
657 | |||||
658 | rMovedList.push_back(pS); | ||||
659 | |||||
660 | if( pS != pT ) | ||||
661 | { | ||||
662 | SwFrameFormat* pTFormat = pT->GetFrameFormat(); | ||||
663 | const SfxItemSet* pSSet = rBox.GetItemSet( nS, i ); | ||||
664 | |||||
665 | if( pSSet || | ||||
666 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMAT ) || | ||||
667 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMULA ) || | ||||
668 | SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_VALUE ) ) | ||||
669 | { | ||||
670 | pTFormat = const_cast<SwTableBox*>(pT)->ClaimFrameFormat(); | ||||
671 | pTFormat->LockModify(); | ||||
672 | if( pTFormat->ResetFormatAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) | ||||
673 | pTFormat->ResetFormatAttr( RES_VERT_ORIENT ); | ||||
674 | |||||
675 | if( pSSet ) | ||||
676 | pTFormat->SetFormatAttr( *pSSet ); | ||||
677 | pTFormat->UnlockModify(); | ||||
678 | } | ||||
679 | } | ||||
680 | } | ||||
681 | } | ||||
682 | |||||
683 | /// Move a single Cell | ||||
684 | void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar, | ||||
685 | bool bMovedBefore, SwUndoSort* pUD) | ||||
686 | { | ||||
687 | OSL_ENSURE(pSource && pTar,"Source or target missing")do { if (true && (!(pSource && pTar))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "687" ": "), "%s", "Source or target missing"); } } while (false); | ||||
688 | |||||
689 | if(pSource == pTar) | ||||
690 | return; | ||||
691 | |||||
692 | if(pUD) | ||||
693 | pUD->Insert( pSource->GetName(), pTar->GetName() ); | ||||
694 | |||||
695 | // Set Pam source to the first ContentNode | ||||
696 | SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() ); | ||||
697 | SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart ); | ||||
698 | |||||
699 | // If the Cell (Source) wasn't moved | ||||
700 | // -> insert an empty Node and move the rest or the Mark | ||||
701 | // points to the first ContentNode | ||||
702 | if( pNd->StartOfSectionNode() == pSource->GetSttNd() ) | ||||
703 | pNd = pDoc->GetNodes().MakeTextNode( aRg.aStart, | ||||
704 | pDoc->GetDfltTextFormatColl() ); | ||||
705 | aRg.aEnd = *pNd->EndOfSectionNode(); | ||||
706 | |||||
707 | // If the Target is empty (there is one empty Node) | ||||
708 | // -> move and delete it | ||||
709 | SwNodeIndex aTar( *pTar->GetSttNd() ); | ||||
710 | pNd = pDoc->GetNodes().GoNext( &aTar ); // next ContentNode | ||||
711 | sal_uLong nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex(); | ||||
712 | |||||
713 | bool bDelFirst = false; | ||||
714 | if( nCount == 2 ) | ||||
715 | { | ||||
716 | OSL_ENSURE( pNd->GetContentNode(), "No ContentNode")do { if (true && (!(pNd->GetContentNode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "716" ": "), "%s", "No ContentNode"); } } while (false); | ||||
717 | bDelFirst = !pNd->GetContentNode()->Len() && bMovedBefore; | ||||
718 | } | ||||
719 | |||||
720 | if(!bDelFirst) | ||||
721 | { // We already have Content -> old Content Section Down | ||||
722 | SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() ); | ||||
723 | pDoc->GetNodes().SectionDown( &aRgTar ); | ||||
724 | } | ||||
725 | |||||
726 | // Insert the Source | ||||
727 | SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() ); | ||||
728 | pDoc->getIDocumentContentOperations().MoveNodeRange( aRg, aIns, | ||||
729 | SwMoveFlags::DEFAULT ); | ||||
730 | |||||
731 | // If first Node is empty -> delete it | ||||
732 | if(bDelFirst) | ||||
733 | pDoc->GetNodes().Delete( aTar ); | ||||
734 | } | ||||
735 | |||||
736 | /// Generate two-dimensional array of FndBoxes | ||||
737 | FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const FndBox_& rBoxRef) : | ||||
738 | m_pDoc(pDocPtr), | ||||
739 | m_nRow(0), | ||||
740 | m_nCol(0) | ||||
741 | { // If the array is symmetric | ||||
742 | m_bSym = CheckLineSymmetry(rBoxRef); | ||||
743 | if( !m_bSym
| ||||
744 | return; | ||||
745 | |||||
746 | // Determine column/row count | ||||
747 | m_nCols = GetColCount(rBoxRef); | ||||
748 | m_nRows = GetRowCount(rBoxRef); | ||||
749 | |||||
750 | // Create linear array | ||||
751 | size_t nCount = static_cast<size_t>(m_nRows) * m_nCols; | ||||
752 | m_pArr = std::make_unique<FndBox_ const *[]>(nCount); | ||||
753 | memset(m_pArr.get(), 0, sizeof(const FndBox_*) * nCount); | ||||
754 | |||||
755 | FillFlat( rBoxRef ); | ||||
756 | } | ||||
757 | |||||
758 | FlatFndBox::~FlatFndBox() | ||||
759 | { | ||||
760 | } | ||||
761 | |||||
762 | /// All Lines of a Box need to have same number of Boxes | ||||
763 | bool FlatFndBox::CheckLineSymmetry(const FndBox_& rBox) | ||||
764 | { | ||||
765 | const FndLines_t &rLines = rBox.GetLines(); | ||||
766 | FndBoxes_t::size_type nBoxes {0}; | ||||
767 | |||||
768 | for (FndLines_t::size_type i=0; i < rLines.size(); ++i) | ||||
769 | { | ||||
770 | const FndLine_* pLn = rLines[i].get(); | ||||
771 | const FndBoxes_t& rBoxes = pLn->GetBoxes(); | ||||
772 | |||||
773 | // Number of Boxes of all Lines is unequal -> no symmetry | ||||
774 | if( i && nBoxes != rBoxes.size()) | ||||
775 | return false; | ||||
776 | |||||
777 | nBoxes = rBoxes.size(); | ||||
778 | if( !CheckBoxSymmetry( *pLn ) ) | ||||
779 | return false; | ||||
780 | } | ||||
781 | return true; | ||||
782 | } | ||||
783 | |||||
784 | /// Check Box for symmetry (All Boxes of a Line need to have same number of Lines) | ||||
785 | bool FlatFndBox::CheckBoxSymmetry(const FndLine_& rLn) | ||||
786 | { | ||||
787 | const FndBoxes_t &rBoxes = rLn.GetBoxes(); | ||||
788 | FndLines_t::size_type nLines {0}; | ||||
789 | |||||
790 | for (FndBoxes_t::size_type i = 0; i < rBoxes.size(); ++i) | ||||
791 | { | ||||
792 | FndBox_ const*const pBox = rBoxes[i].get(); | ||||
793 | const FndLines_t& rLines = pBox->GetLines(); | ||||
794 | |||||
795 | // Number of Lines of all Boxes is unequal -> no symmetry | ||||
796 | if( i && nLines != rLines.size() ) | ||||
797 | return false; | ||||
798 | |||||
799 | nLines = rLines.size(); | ||||
800 | if( nLines && !CheckLineSymmetry( *pBox ) ) | ||||
801 | return false; | ||||
802 | } | ||||
803 | return true; | ||||
804 | } | ||||
805 | |||||
806 | /// Maximum count of Columns (Boxes) | ||||
807 | sal_uInt16 FlatFndBox::GetColCount(const FndBox_& rBox) | ||||
808 | { | ||||
809 | const FndLines_t& rLines = rBox.GetLines(); | ||||
810 | // Iterate over Lines | ||||
811 | if( rLines.empty() ) | ||||
812 | return 1; | ||||
813 | |||||
814 | sal_uInt16 nSum = 0; | ||||
815 | for (const auto & pLine : rLines) | ||||
816 | { | ||||
817 | // The Boxes of a Line | ||||
818 | sal_uInt16 nCount = 0; | ||||
819 | const FndBoxes_t& rBoxes = pLine->GetBoxes(); | ||||
820 | for (const auto &rpB : rBoxes) | ||||
821 | { // Iterate recursively over the Lines | ||||
822 | nCount += rpB->GetLines().empty() ? 1 : GetColCount(*rpB); | ||||
823 | } | ||||
824 | |||||
825 | if( nSum < nCount ) | ||||
826 | nSum = nCount; | ||||
827 | } | ||||
828 | return nSum; | ||||
829 | } | ||||
830 | |||||
831 | /// Maximum count of Rows (Lines) | ||||
832 | sal_uInt16 FlatFndBox::GetRowCount(const FndBox_& rBox) | ||||
833 | { | ||||
834 | const FndLines_t& rLines = rBox.GetLines(); | ||||
835 | if( rLines.empty() ) | ||||
836 | return 1; | ||||
837 | |||||
838 | sal_uInt16 nLines = 0; | ||||
839 | for (const auto & pLine : rLines) | ||||
840 | { // The Boxes of a Line | ||||
841 | const FndBoxes_t& rBoxes = pLine->GetBoxes(); | ||||
842 | sal_uInt16 nLn = 1; | ||||
843 | for (const auto &rpB : rBoxes) | ||||
844 | { | ||||
845 | if (!rpB->GetLines().empty()) | ||||
846 | { // Iterate recursively over the Lines | ||||
847 | nLn = std::max(GetRowCount(*rpB), nLn); | ||||
848 | } | ||||
849 | } | ||||
850 | |||||
851 | nLines = nLines + nLn; | ||||
852 | } | ||||
853 | return nLines; | ||||
854 | } | ||||
855 | |||||
856 | /// Create a linear array of atomic FndBoxes | ||||
857 | void FlatFndBox::FillFlat(const FndBox_& rBox, bool bLastBox) | ||||
858 | { | ||||
859 | bool bModRow = false; | ||||
860 | const FndLines_t& rLines = rBox.GetLines(); | ||||
861 | |||||
862 | // Iterate over Lines | ||||
863 | sal_uInt16 nOldRow = m_nRow; | ||||
864 | for (const auto & pLine : rLines) | ||||
865 | { | ||||
866 | // The Boxes of a Line | ||||
867 | const FndBoxes_t& rBoxes = pLine->GetBoxes(); | ||||
868 | sal_uInt16 nOldCol = m_nCol; | ||||
869 | for( FndBoxes_t::size_type j = 0; j < rBoxes.size(); ++j ) | ||||
870 | { | ||||
871 | // Check the Box if it's an atomic one | ||||
872 | const FndBox_ *const pBox = rBoxes[j].get(); | ||||
873 | |||||
874 | if( pBox->GetLines().empty() ) | ||||
875 | { | ||||
876 | // save it | ||||
877 | sal_uInt16 nOff = m_nRow * m_nCols + m_nCol; | ||||
878 | m_pArr[nOff] = pBox; | ||||
| |||||
879 | |||||
880 | // Save the Formula/Format/Value values | ||||
881 | const SwFrameFormat* pFormat = pBox->GetBox()->GetFrameFormat(); | ||||
882 | if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMAT ) || | ||||
883 | SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA ) || | ||||
884 | SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE ) ) | ||||
885 | { | ||||
886 | auto pSet = std::make_unique<SfxItemSet>( | ||||
887 | m_pDoc->GetAttrPool(), | ||||
888 | svl::Items< | ||||
889 | RES_VERT_ORIENT, RES_VERT_ORIENT, | ||||
890 | RES_BOXATR_FORMAT, RES_BOXATR_VALUE>{}); | ||||
891 | pSet->Put( pFormat->GetAttrSet() ); | ||||
892 | if( m_ppItemSets.empty() ) | ||||
893 | { | ||||
894 | size_t nCount = static_cast<size_t>(m_nRows) * m_nCols; | ||||
895 | m_ppItemSets.resize(nCount); | ||||
896 | } | ||||
897 | m_ppItemSets[nOff] = std::move(pSet); | ||||
898 | } | ||||
899 | |||||
900 | bModRow = true; | ||||
901 | } | ||||
902 | else | ||||
903 | { | ||||
904 | // Iterate recursively over the Lines of a Box | ||||
905 | FillFlat( *pBox, ( j+1 == rBoxes.size() ) ); | ||||
906 | } | ||||
907 | m_nCol++; | ||||
908 | } | ||||
909 | if(bModRow) | ||||
910 | m_nRow++; | ||||
911 | m_nCol = nOldCol; | ||||
912 | } | ||||
913 | if(!bLastBox) | ||||
914 | m_nRow = nOldRow; | ||||
915 | } | ||||
916 | |||||
917 | /// Access a specific Cell | ||||
918 | const FndBox_* FlatFndBox::GetBox(sal_uInt16 n_Col, sal_uInt16 n_Row) const | ||||
919 | { | ||||
920 | sal_uInt16 nOff = n_Row * m_nCols + n_Col; | ||||
921 | const FndBox_* pTmp = m_pArr[nOff]; | ||||
922 | |||||
923 | OSL_ENSURE(n_Col < m_nCols && n_Row < m_nRows && pTmp, "invalid array access")do { if (true && (!(n_Col < m_nCols && n_Row < m_nRows && pTmp))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "923" ": "), "%s", "invalid array access"); } } while (false ); | ||||
924 | return pTmp; | ||||
925 | } | ||||
926 | |||||
927 | const SfxItemSet* FlatFndBox::GetItemSet(sal_uInt16 n_Col, sal_uInt16 n_Row) const | ||||
928 | { | ||||
929 | OSL_ENSURE( m_ppItemSets.empty() || ( n_Col < m_nCols && n_Row < m_nRows), "invalid array access")do { if (true && (!(m_ppItemSets.empty() || ( n_Col < m_nCols && n_Row < m_nRows)))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/docsort.cxx" ":" "929" ": "), "%s", "invalid array access"); } } while (false ); | ||||
930 | |||||
931 | return !m_ppItemSets.empty() ? m_ppItemSets[unsigned(n_Row * m_nCols) + n_Col].get() : nullptr; | ||||
932 | } | ||||
933 | |||||
934 | sal_uInt16 SwMovedBoxes::GetPos(const SwTableBox* pTableBox) const | ||||
935 | { | ||||
936 | std::vector<const SwTableBox*>::const_iterator it = std::find(mBoxes.begin(), mBoxes.end(), pTableBox); | ||||
937 | return it == mBoxes.end() ? USHRT_MAX(32767 *2 +1) : it - mBoxes.begin(); | ||||
938 | } | ||||
939 | |||||
940 | /* 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 */ |