File: | home/maarten/src/libreoffice/core/sc/source/core/tool/rangenam.cxx |
Warning: | line 128, column 83 Forming reference to null pointer |
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 <string.h> | |||
21 | #include <memory> | |||
22 | #include <unotools/collatorwrapper.hxx> | |||
23 | #include <unotools/transliterationwrapper.hxx> | |||
24 | #include <unotools/charclass.hxx> | |||
25 | #include <com/sun/star/sheet/NamedRangeFlag.hpp> | |||
26 | #include <osl/diagnose.h> | |||
27 | ||||
28 | #include <token.hxx> | |||
29 | #include <tokenarray.hxx> | |||
30 | #include <rangenam.hxx> | |||
31 | #include <global.hxx> | |||
32 | #include <compiler.hxx> | |||
33 | #include <rangeutl.hxx> | |||
34 | #include <rechead.hxx> | |||
35 | #include <refupdat.hxx> | |||
36 | #include <document.hxx> | |||
37 | #include <refupdatecontext.hxx> | |||
38 | #include <tokenstringcontext.hxx> | |||
39 | ||||
40 | #include <formula/errorcodes.hxx> | |||
41 | ||||
42 | using namespace formula; | |||
43 | using ::std::pair; | |||
44 | ||||
45 | // ScRangeData | |||
46 | ||||
47 | ScRangeData::ScRangeData( ScDocument& rDok, | |||
48 | const OUString& rName, | |||
49 | const OUString& rSymbol, | |||
50 | const ScAddress& rAddress, | |||
51 | Type nType, | |||
52 | const FormulaGrammar::Grammar eGrammar ) : | |||
53 | aName ( rName ), | |||
54 | aUpperName ( ScGlobal::getCharClassPtr()->uppercase( rName ) ), | |||
55 | aPos ( rAddress ), | |||
56 | eType ( nType ), | |||
57 | rDoc ( rDok ), | |||
58 | eTempGrammar( eGrammar ), | |||
59 | nIndex ( 0 ), | |||
60 | bModified ( false ) | |||
61 | { | |||
62 | if (!rSymbol.isEmpty()) | |||
63 | { | |||
64 | // Let the compiler set an error on unknown names for a subsequent | |||
65 | // CompileUnresolvedXML(). | |||
66 | const bool bImporting = rDoc.IsImportingXML(); | |||
67 | CompileRangeData( rSymbol, bImporting); | |||
68 | if (bImporting) | |||
69 | rDoc.CheckLinkFormulaNeedingCheck( *pCode); | |||
70 | } | |||
71 | else | |||
72 | { | |||
73 | // #i63513#/#i65690# don't leave pCode as NULL. | |||
74 | // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too, | |||
75 | // to ensure same behavior if unnecessary copying is left out. | |||
76 | ||||
77 | pCode.reset( new ScTokenArray(rDoc) ); | |||
78 | pCode->SetFromRangeName(true); | |||
79 | } | |||
80 | } | |||
81 | ||||
82 | ScRangeData::ScRangeData( ScDocument& rDok, | |||
83 | const OUString& rName, | |||
84 | const ScTokenArray& rArr, | |||
85 | const ScAddress& rAddress, | |||
86 | Type nType ) : | |||
87 | aName ( rName ), | |||
88 | aUpperName ( ScGlobal::getCharClassPtr()->uppercase( rName ) ), | |||
89 | pCode ( new ScTokenArray( rArr ) ), | |||
90 | aPos ( rAddress ), | |||
91 | eType ( nType ), | |||
92 | rDoc ( rDok ), | |||
93 | eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ), | |||
94 | nIndex ( 0 ), | |||
95 | bModified ( false ) | |||
96 | { | |||
97 | pCode->SetFromRangeName(true); | |||
98 | InitCode(); | |||
99 | } | |||
100 | ||||
101 | ScRangeData::ScRangeData( ScDocument& rDok, | |||
102 | const OUString& rName, | |||
103 | const ScAddress& rTarget ) : | |||
104 | aName ( rName ), | |||
105 | aUpperName ( ScGlobal::getCharClassPtr()->uppercase( rName ) ), | |||
106 | pCode ( new ScTokenArray(rDok) ), | |||
107 | aPos ( rTarget ), | |||
108 | eType ( Type::Name ), | |||
109 | rDoc ( rDok ), | |||
110 | eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ), | |||
111 | nIndex ( 0 ), | |||
112 | bModified ( false ) | |||
113 | { | |||
114 | ScSingleRefData aRefData; | |||
115 | aRefData.InitAddress( rTarget ); | |||
116 | aRefData.SetFlag3D( true ); | |||
117 | pCode->AddSingleReference( aRefData ); | |||
118 | pCode->SetFromRangeName(true); | |||
119 | ScCompiler aComp( rDoc, aPos, *pCode, rDoc.GetGrammar() ); | |||
120 | aComp.CompileTokenArray(); | |||
121 | if ( pCode->GetCodeError() == FormulaError::NONE ) | |||
122 | eType |= Type::AbsPos; | |||
123 | } | |||
124 | ||||
125 | ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* pDocument, const ScAddress* pPos) : | |||
126 | aName (rScRangeData.aName), | |||
127 | aUpperName (rScRangeData.aUpperName), | |||
128 | pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone().release() : new ScTokenArray(*pDocument)), // make real copy (not copy-ctor) | |||
| ||||
129 | aPos (pPos ? *pPos : rScRangeData.aPos), | |||
130 | eType (rScRangeData.eType), | |||
131 | rDoc (pDocument ? *pDocument : rScRangeData.rDoc), | |||
132 | eTempGrammar(rScRangeData.eTempGrammar), | |||
133 | nIndex (rScRangeData.nIndex), | |||
134 | bModified (rScRangeData.bModified) | |||
135 | { | |||
136 | pCode->SetFromRangeName(true); | |||
137 | } | |||
138 | ||||
139 | ScRangeData::~ScRangeData() | |||
140 | { | |||
141 | } | |||
142 | ||||
143 | void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError ) | |||
144 | { | |||
145 | if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED) | |||
146 | { | |||
147 | OSL_FAIL( "ScRangeData::CompileRangeData: unspecified grammar")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/rangenam.cxx" ":" "147" ": "), "%s", "ScRangeData::CompileRangeData: unspecified grammar" ); } } while (false); | |||
148 | // Anything is almost as bad as this, but we might have the best choice | |||
149 | // if not loading documents. | |||
150 | eTempGrammar = FormulaGrammar::GRAM_NATIVE; | |||
151 | } | |||
152 | ||||
153 | ScCompiler aComp( rDoc, aPos, eTempGrammar ); | |||
154 | if (bSetError) | |||
155 | aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_NO_BREAK); | |||
156 | pCode = aComp.CompileString( rSymbol ); | |||
157 | pCode->SetFromRangeName(true); | |||
158 | if( pCode->GetCodeError() != FormulaError::NONE ) | |||
159 | return; | |||
160 | ||||
161 | FormulaTokenArrayPlainIterator aIter(*pCode); | |||
162 | FormulaToken* p = aIter.GetNextReference(); | |||
163 | if( p ) | |||
164 | { | |||
165 | // first token is a reference | |||
166 | /* FIXME: wouldn't that need a check if it's exactly one reference? */ | |||
167 | if( p->GetType() == svSingleRef ) | |||
168 | eType = eType | Type::AbsPos; | |||
169 | else | |||
170 | eType = eType | Type::AbsArea; | |||
171 | } | |||
172 | // For manual input set an error for an incomplete formula. | |||
173 | if (!rDoc.IsImportingXML()) | |||
174 | { | |||
175 | aComp.CompileTokenArray(); | |||
176 | pCode->DelRPN(); | |||
177 | } | |||
178 | } | |||
179 | ||||
180 | void ScRangeData::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt ) | |||
181 | { | |||
182 | if (pCode->GetCodeError() == FormulaError::NoName) | |||
183 | { | |||
184 | // Reconstruct the symbol/formula and then recompile. | |||
185 | OUString aSymbol; | |||
186 | rCxt.setGrammar(eTempGrammar); | |||
187 | ScCompiler aComp(rCxt, aPos, *pCode); | |||
188 | aComp.CreateStringFromTokenArray( aSymbol); | |||
189 | // Don't let the compiler set an error for unknown names on final | |||
190 | // compile, errors are handled by the interpreter thereafter. | |||
191 | CompileRangeData( aSymbol, false); | |||
192 | rCxt.getDoc().CheckLinkFormulaNeedingCheck( *pCode); | |||
193 | } | |||
194 | } | |||
195 | ||||
196 | #if DEBUG_FORMULA_COMPILER0 | |||
197 | void ScRangeData::Dump() const | |||
198 | { | |||
199 | cout << "-- ScRangeData" << endl; | |||
200 | cout << " name: " << aName << endl; | |||
201 | cout << " ref position: (col=" << aPos.Col() << ", row=" << aPos.Row() << ", sheet=" << aPos.Tab() << ")" << endl; | |||
202 | ||||
203 | if (pCode) | |||
204 | pCode->Dump(); | |||
205 | } | |||
206 | #endif | |||
207 | ||||
208 | void ScRangeData::GuessPosition() | |||
209 | { | |||
210 | // set a position that allows "absoluting" of all relative references | |||
211 | // in CalcAbsIfRel without errors | |||
212 | ||||
213 | OSL_ENSURE(aPos == ScAddress(), "position will go lost now")do { if (true && (!(aPos == ScAddress()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/rangenam.cxx" ":" "213" ": "), "%s", "position will go lost now"); } } while (false); | |||
214 | ||||
215 | SCCOL nMinCol = 0; | |||
216 | SCROW nMinRow = 0; | |||
217 | SCTAB nMinTab = 0; | |||
218 | ||||
219 | formula::FormulaToken* t; | |||
220 | formula::FormulaTokenArrayPlainIterator aIter(*pCode); | |||
221 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
222 | { | |||
223 | ScSingleRefData& rRef1 = *t->GetSingleRef(); | |||
224 | if ( rRef1.IsColRel() && rRef1.Col() < nMinCol ) | |||
225 | nMinCol = rRef1.Col(); | |||
226 | if ( rRef1.IsRowRel() && rRef1.Row() < nMinRow ) | |||
227 | nMinRow = rRef1.Row(); | |||
228 | if ( rRef1.IsTabRel() && rRef1.Tab() < nMinTab ) | |||
229 | nMinTab = rRef1.Tab(); | |||
230 | ||||
231 | if ( t->GetType() == svDoubleRef ) | |||
232 | { | |||
233 | ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2; | |||
234 | if ( rRef2.IsColRel() && rRef2.Col() < nMinCol ) | |||
235 | nMinCol = rRef2.Col(); | |||
236 | if ( rRef2.IsRowRel() && rRef2.Row() < nMinRow ) | |||
237 | nMinRow = rRef2.Row(); | |||
238 | if ( rRef2.IsTabRel() && rRef2.Tab() < nMinTab ) | |||
239 | nMinTab = rRef2.Tab(); | |||
240 | } | |||
241 | } | |||
242 | ||||
243 | aPos = ScAddress( static_cast<SCCOL>(-nMinCol), static_cast<SCROW>(-nMinRow), static_cast<SCTAB>(-nMinTab) ); | |||
244 | } | |||
245 | ||||
246 | void ScRangeData::GetSymbol( OUString& rSymbol, const FormulaGrammar::Grammar eGrammar ) const | |||
247 | { | |||
248 | ScCompiler aComp(rDoc, aPos, *pCode, eGrammar); | |||
249 | aComp.CreateStringFromTokenArray( rSymbol ); | |||
250 | } | |||
251 | ||||
252 | void ScRangeData::GetSymbol( OUString& rSymbol, const ScAddress& rPos, const FormulaGrammar::Grammar eGrammar ) const | |||
253 | { | |||
254 | OUString aStr; | |||
255 | ScCompiler aComp(rDoc, rPos, *pCode, eGrammar); | |||
256 | aComp.CreateStringFromTokenArray( aStr ); | |||
257 | rSymbol = aStr; | |||
258 | } | |||
259 | ||||
260 | void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos ) | |||
261 | { | |||
262 | std::unique_ptr<ScTokenArray> pTemp( pCode->Clone() ); | |||
263 | ScCompiler aComp(rDoc, rPos, *pTemp, formula::FormulaGrammar::GRAM_DEFAULT); | |||
264 | aComp.MoveRelWrap(); | |||
265 | aComp.CreateStringFromTokenArray( rBuffer ); | |||
266 | } | |||
267 | ||||
268 | void ScRangeData::UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab ) | |||
269 | { | |||
270 | sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt, aPos); | |||
271 | bModified = aRes.mbReferenceModified; | |||
272 | if (aRes.mbReferenceModified) | |||
273 | rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex); | |||
274 | } | |||
275 | ||||
276 | void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest ) | |||
277 | { | |||
278 | bool bChanged = false; | |||
279 | ||||
280 | formula::FormulaToken* t; | |||
281 | formula::FormulaTokenArrayPlainIterator aIter(*pCode); | |||
282 | ||||
283 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
284 | { | |||
285 | if( t->GetType() != svIndex ) | |||
286 | { | |||
287 | SingleDoubleRefModifier aMod( *t ); | |||
288 | ScComplexRefData& rRef = aMod.Ref(); | |||
289 | if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() && | |||
290 | (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) && | |||
291 | ( t->GetType() == svSingleRef || | |||
292 | (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() && | |||
293 | (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel())))) | |||
294 | { | |||
295 | ScRange aAbs = rRef.toAbs(rDoc, aPos); | |||
296 | if (ScRefUpdate::UpdateTranspose(rDoc, rSource, rDest, aAbs) != UR_NOTHING) | |||
297 | { | |||
298 | rRef.SetRange(rDoc.GetSheetLimits(), aAbs, aPos); | |||
299 | bChanged = true; | |||
300 | } | |||
301 | } | |||
302 | } | |||
303 | } | |||
304 | ||||
305 | bModified = bChanged; | |||
306 | } | |||
307 | ||||
308 | void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) | |||
309 | { | |||
310 | bool bChanged = false; | |||
311 | ||||
312 | formula::FormulaToken* t; | |||
313 | formula::FormulaTokenArrayPlainIterator aIter(*pCode); | |||
314 | ||||
315 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
316 | { | |||
317 | if( t->GetType() != svIndex ) | |||
318 | { | |||
319 | SingleDoubleRefModifier aMod( *t ); | |||
320 | ScComplexRefData& rRef = aMod.Ref(); | |||
321 | if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() && | |||
322 | (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) && | |||
323 | ( t->GetType() == svSingleRef || | |||
324 | (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() && | |||
325 | (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel())))) | |||
326 | { | |||
327 | ScRange aAbs = rRef.toAbs(rDoc, aPos); | |||
328 | if (ScRefUpdate::UpdateGrow(rArea, nGrowX, nGrowY, aAbs) != UR_NOTHING) | |||
329 | { | |||
330 | rRef.SetRange(rDoc.GetSheetLimits(), aAbs, aPos); | |||
331 | bChanged = true; | |||
332 | } | |||
333 | } | |||
334 | } | |||
335 | } | |||
336 | ||||
337 | bModified = bChanged; // has to be evaluated immediately afterwards | |||
338 | } | |||
339 | ||||
340 | bool ScRangeData::operator== (const ScRangeData& rData) const // for Undo | |||
341 | { | |||
342 | if ( nIndex != rData.nIndex || | |||
343 | aName != rData.aName || | |||
344 | aPos != rData.aPos || | |||
345 | eType != rData.eType ) return false; | |||
346 | ||||
347 | sal_uInt16 nLen = pCode->GetLen(); | |||
348 | if ( nLen != rData.pCode->GetLen() ) return false; | |||
349 | ||||
350 | FormulaToken** ppThis = pCode->GetArray(); | |||
351 | FormulaToken** ppOther = rData.pCode->GetArray(); | |||
352 | ||||
353 | for ( sal_uInt16 i=0; i<nLen; i++ ) | |||
354 | if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) ) | |||
355 | return false; | |||
356 | ||||
357 | return true; | |||
358 | } | |||
359 | ||||
360 | bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const | |||
361 | { | |||
362 | bool bRet = false; | |||
363 | ScRange aRange; | |||
364 | if ( IsReference(aRange) ) | |||
365 | bRet = ( rBlock == aRange ); | |||
366 | return bRet; | |||
367 | } | |||
368 | ||||
369 | bool ScRangeData::IsReference( ScRange& rRange ) const | |||
370 | { | |||
371 | if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos )) && pCode ) | |||
372 | return pCode->IsReference(rRange, aPos); | |||
373 | ||||
374 | return false; | |||
375 | } | |||
376 | ||||
377 | bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const | |||
378 | { | |||
379 | if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode ) | |||
380 | return pCode->IsReference(rRange, rPos); | |||
381 | ||||
382 | return false; | |||
383 | } | |||
384 | ||||
385 | bool ScRangeData::IsValidReference( ScRange& rRange ) const | |||
386 | { | |||
387 | if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode ) | |||
388 | return pCode->IsValidReference(rRange, aPos); | |||
389 | ||||
390 | return false; | |||
391 | } | |||
392 | ||||
393 | void ScRangeData::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab ) | |||
394 | { | |||
395 | sc::RefUpdateResult aRes = pCode->AdjustReferenceOnInsertedTab(rCxt, aPos); | |||
396 | if (aRes.mbReferenceModified) | |||
397 | rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex); | |||
398 | ||||
399 | if (rCxt.mnInsertPos <= aPos.Tab()) | |||
400 | aPos.IncTab(rCxt.mnSheets); | |||
401 | } | |||
402 | ||||
403 | void ScRangeData::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab ) | |||
404 | { | |||
405 | sc::RefUpdateResult aRes = pCode->AdjustReferenceOnDeletedTab(rCxt, aPos); | |||
406 | if (aRes.mbReferenceModified) | |||
407 | rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex); | |||
408 | ||||
409 | if (rCxt.mnDeletePos <= aPos.Tab()) | |||
410 | aPos.IncTab(-rCxt.mnSheets); | |||
411 | } | |||
412 | ||||
413 | void ScRangeData::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab ) | |||
414 | { | |||
415 | sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMovedTab(rCxt, aPos); | |||
416 | if (aRes.mbReferenceModified) | |||
417 | rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex); | |||
418 | ||||
419 | aPos.SetTab(rCxt.getNewTab(aPos.Tab())); | |||
420 | } | |||
421 | ||||
422 | void ScRangeData::MakeValidName( const ScDocument& rDoc, OUString& rName ) | |||
423 | { | |||
424 | ||||
425 | // strip leading invalid characters | |||
426 | sal_Int32 nPos = 0; | |||
427 | sal_Int32 nLen = rName.getLength(); | |||
428 | while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) ) | |||
429 | ++nPos; | |||
430 | if ( nPos>0 ) | |||
431 | rName = rName.copy(nPos); | |||
432 | ||||
433 | // if the first character is an invalid start character, precede with '_' | |||
434 | if ( !rName.isEmpty() && !ScCompiler::IsCharFlagAllConventions( rName, 0, ScCharFlags::CharName ) ) | |||
435 | rName = "_" + rName; | |||
436 | ||||
437 | // replace invalid with '_' | |||
438 | nLen = rName.getLength(); | |||
439 | for (nPos=0; nPos<nLen; nPos++) | |||
440 | { | |||
441 | if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) ) | |||
442 | rName = rName.replaceAt( nPos, 1, "_" ); | |||
443 | } | |||
444 | ||||
445 | // Ensure that the proposed name is not a reference under any convention, | |||
446 | // same as in IsNameValid() | |||
447 | ScAddress aAddr; | |||
448 | ScRange aRange; | |||
449 | for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) | |||
450 | { | |||
451 | ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); | |||
452 | // Don't check Parse on VALID, any partial only VALID may result in | |||
453 | // #REF! during compile later! | |||
454 | while (aRange.Parse(rName, rDoc, details) != ScRefFlags::ZERO || | |||
455 | aAddr.Parse(rName, rDoc, details) != ScRefFlags::ZERO) | |||
456 | { | |||
457 | // Range Parse is partially valid also with invalid sheet name, | |||
458 | // Address Parse ditto, during compile name would generate a #REF! | |||
459 | if ( rName.indexOf( '.' ) != -1 ) | |||
460 | rName = rName.replaceFirst( ".", "_" ); | |||
461 | else | |||
462 | rName = "_" + rName; | |||
463 | } | |||
464 | } | |||
465 | } | |||
466 | ||||
467 | ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, const ScDocument& rDoc ) | |||
468 | { | |||
469 | /* XXX If changed, sc/source/filter/ftools/ftools.cxx | |||
470 | * ScfTools::ConvertToScDefinedName needs to be changed too. */ | |||
471 | char const a('.'); | |||
472 | if (rName.indexOf(a) != -1) | |||
473 | return NAME_INVALID_BAD_STRING; | |||
474 | sal_Int32 nPos = 0; | |||
475 | sal_Int32 nLen = rName.getLength(); | |||
476 | if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::CharName ) ) | |||
477 | return NAME_INVALID_BAD_STRING; | |||
478 | while ( nPos < nLen ) | |||
479 | { | |||
480 | if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::Name ) ) | |||
481 | return NAME_INVALID_BAD_STRING; | |||
482 | } | |||
483 | ScAddress aAddr; | |||
484 | ScRange aRange; | |||
485 | for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) | |||
486 | { | |||
487 | ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); | |||
488 | // Don't check Parse on VALID, any partial only VALID may result in | |||
489 | // #REF! during compile later! | |||
490 | if (aRange.Parse(rName, rDoc, details) != ScRefFlags::ZERO || | |||
491 | aAddr.Parse(rName, rDoc, details) != ScRefFlags::ZERO ) | |||
492 | { | |||
493 | return NAME_INVALID_CELL_REF; | |||
494 | } | |||
495 | } | |||
496 | return NAME_VALID; | |||
497 | } | |||
498 | ||||
499 | FormulaError ScRangeData::GetErrCode() const | |||
500 | { | |||
501 | return pCode ? pCode->GetCodeError() : FormulaError::NONE; | |||
502 | } | |||
503 | ||||
504 | bool ScRangeData::HasReferences() const | |||
505 | { | |||
506 | return pCode->HasReferences(); | |||
507 | } | |||
508 | ||||
509 | sal_uInt32 ScRangeData::GetUnoType() const | |||
510 | { | |||
511 | sal_uInt32 nUnoType = 0; | |||
512 | if ( HasType(Type::Criteria) ) nUnoType |= css::sheet::NamedRangeFlag::FILTER_CRITERIA; | |||
513 | if ( HasType(Type::PrintArea) ) nUnoType |= css::sheet::NamedRangeFlag::PRINT_AREA; | |||
514 | if ( HasType(Type::ColHeader) ) nUnoType |= css::sheet::NamedRangeFlag::COLUMN_HEADER; | |||
515 | if ( HasType(Type::RowHeader) ) nUnoType |= css::sheet::NamedRangeFlag::ROW_HEADER; | |||
516 | return nUnoType; | |||
517 | } | |||
518 | ||||
519 | void ScRangeData::ValidateTabRefs() | |||
520 | { | |||
521 | // try to make sure all relative references and the reference position | |||
522 | // are within existing tables, so they can be represented as text | |||
523 | // (if the range of used tables is more than the existing tables, | |||
524 | // the result may still contain invalid tables, because the relative | |||
525 | // references aren't changed so formulas stay the same) | |||
526 | ||||
527 | // find range of used tables | |||
528 | ||||
529 | SCTAB nMinTab = aPos.Tab(); | |||
530 | SCTAB nMaxTab = nMinTab; | |||
531 | formula::FormulaToken* t; | |||
532 | formula::FormulaTokenArrayPlainIterator aIter(*pCode); | |||
533 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
534 | { | |||
535 | ScSingleRefData& rRef1 = *t->GetSingleRef(); | |||
536 | ScAddress aAbs = rRef1.toAbs(rDoc, aPos); | |||
537 | if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() ) | |||
538 | { | |||
539 | if (aAbs.Tab() < nMinTab) | |||
540 | nMinTab = aAbs.Tab(); | |||
541 | if (aAbs.Tab() > nMaxTab) | |||
542 | nMaxTab = aAbs.Tab(); | |||
543 | } | |||
544 | if ( t->GetType() == svDoubleRef ) | |||
545 | { | |||
546 | ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2; | |||
547 | aAbs = rRef2.toAbs(rDoc, aPos); | |||
548 | if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() ) | |||
549 | { | |||
550 | if (aAbs.Tab() < nMinTab) | |||
551 | nMinTab = aAbs.Tab(); | |||
552 | if (aAbs.Tab() > nMaxTab) | |||
553 | nMaxTab = aAbs.Tab(); | |||
554 | } | |||
555 | } | |||
556 | } | |||
557 | ||||
558 | SCTAB nTabCount = rDoc.GetTableCount(); | |||
559 | if ( nMaxTab < nTabCount || nMinTab <= 0 ) | |||
560 | return; | |||
561 | ||||
562 | // move position and relative tab refs | |||
563 | // The formulas that use the name are not changed by this | |||
564 | ||||
565 | SCTAB nMove = nMinTab; | |||
566 | ScAddress aOldPos = aPos; | |||
567 | aPos.SetTab( aPos.Tab() - nMove ); | |||
568 | ||||
569 | aIter.Reset(); | |||
570 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
571 | { | |||
572 | switch (t->GetType()) | |||
573 | { | |||
574 | case svSingleRef: | |||
575 | { | |||
576 | ScSingleRefData& rRef = *t->GetSingleRef(); | |||
577 | if (!rRef.IsTabDeleted()) | |||
578 | { | |||
579 | ScAddress aAbs = rRef.toAbs(rDoc, aOldPos); | |||
580 | rRef.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos); | |||
581 | } | |||
582 | } | |||
583 | break; | |||
584 | case svDoubleRef: | |||
585 | { | |||
586 | ScComplexRefData& rRef = *t->GetDoubleRef(); | |||
587 | if (!rRef.Ref1.IsTabDeleted()) | |||
588 | { | |||
589 | ScAddress aAbs = rRef.Ref1.toAbs(rDoc, aOldPos); | |||
590 | rRef.Ref1.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos); | |||
591 | } | |||
592 | if (!rRef.Ref2.IsTabDeleted()) | |||
593 | { | |||
594 | ScAddress aAbs = rRef.Ref2.toAbs(rDoc, aOldPos); | |||
595 | rRef.Ref2.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos); | |||
596 | } | |||
597 | } | |||
598 | break; | |||
599 | default: | |||
600 | ; | |||
601 | } | |||
602 | } | |||
603 | } | |||
604 | ||||
605 | void ScRangeData::SetCode( const ScTokenArray& rArr ) | |||
606 | { | |||
607 | pCode.reset(new ScTokenArray( rArr )); | |||
608 | pCode->SetFromRangeName(true); | |||
609 | InitCode(); | |||
610 | } | |||
611 | ||||
612 | void ScRangeData::InitCode() | |||
613 | { | |||
614 | if( pCode->GetCodeError() == FormulaError::NONE ) | |||
615 | { | |||
616 | FormulaToken* p = FormulaTokenArrayPlainIterator(*pCode).GetNextReference(); | |||
617 | if( p ) // exact one reference at first | |||
618 | { | |||
619 | if( p->GetType() == svSingleRef ) | |||
620 | eType = eType | Type::AbsPos; | |||
621 | else | |||
622 | eType = eType | Type::AbsArea; | |||
623 | } | |||
624 | } | |||
625 | } | |||
626 | ||||
627 | extern "C" | |||
628 | int ScRangeData_QsortNameCompare( const void* p1, const void* p2 ) | |||
629 | { | |||
630 | return static_cast<int>(ScGlobal::GetCollator()->compareString( | |||
631 | (*static_cast<const ScRangeData* const *>(p1))->GetName(), | |||
632 | (*static_cast<const ScRangeData* const *>(p2))->GetName() )); | |||
633 | } | |||
634 | ||||
635 | namespace { | |||
636 | ||||
637 | /** | |||
638 | * Predicate to check if the name references the specified range. | |||
639 | */ | |||
640 | class MatchByRange | |||
641 | { | |||
642 | const ScRange& mrRange; | |||
643 | public: | |||
644 | explicit MatchByRange(const ScRange& rRange) : mrRange(rRange) {} | |||
645 | bool operator() (std::pair<OUString const, std::unique_ptr<ScRangeData>> const& r) const | |||
646 | { | |||
647 | return r.second->IsRangeAtBlock(mrRange); | |||
648 | } | |||
649 | }; | |||
650 | ||||
651 | } | |||
652 | ||||
653 | ScRangeName::ScRangeName() {} | |||
654 | ||||
655 | ScRangeName::ScRangeName(const ScRangeName& r) | |||
656 | { | |||
657 | for (auto const& it : r.m_Data) | |||
658 | { | |||
659 | m_Data.insert(std::make_pair(it.first, std::make_unique<ScRangeData>(*it.second))); | |||
| ||||
660 | } | |||
661 | // std::map was cloned, so each collection needs its own index to data. | |||
662 | maIndexToData.resize( r.maIndexToData.size(), nullptr); | |||
663 | for (auto const& itr : m_Data) | |||
664 | { | |||
665 | size_t nPos = itr.second->GetIndex() - 1; | |||
666 | if (nPos >= maIndexToData.size()) | |||
667 | { | |||
668 | OSL_FAIL( "ScRangeName copy-ctor: maIndexToData size doesn't fit")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/rangenam.cxx" ":" "668" ": "), "%s", "ScRangeName copy-ctor: maIndexToData size doesn't fit" ); } } while (false); | |||
669 | maIndexToData.resize(nPos+1, nullptr); | |||
670 | } | |||
671 | maIndexToData[nPos] = itr.second.get(); | |||
672 | } | |||
673 | } | |||
674 | ||||
675 | const ScRangeData* ScRangeName::findByRange(const ScRange& rRange) const | |||
676 | { | |||
677 | DataType::const_iterator itr = std::find_if( | |||
678 | m_Data.begin(), m_Data.end(), MatchByRange(rRange)); | |||
679 | return itr == m_Data.end() ? nullptr : itr->second.get(); | |||
680 | } | |||
681 | ||||
682 | ScRangeData* ScRangeName::findByUpperName(const OUString& rName) | |||
683 | { | |||
684 | DataType::iterator itr = m_Data.find(rName); | |||
685 | return itr == m_Data.end() ? nullptr : itr->second.get(); | |||
686 | } | |||
687 | ||||
688 | const ScRangeData* ScRangeName::findByUpperName(const OUString& rName) const | |||
689 | { | |||
690 | DataType::const_iterator itr = m_Data.find(rName); | |||
691 | return itr == m_Data.end() ? nullptr : itr->second.get(); | |||
692 | } | |||
693 | ||||
694 | ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const | |||
695 | { | |||
696 | if (!i) | |||
697 | // index should never be zero. | |||
698 | return nullptr; | |||
699 | ||||
700 | size_t nPos = i - 1; | |||
701 | return nPos < maIndexToData.size() ? maIndexToData[nPos] : nullptr; | |||
702 | } | |||
703 | ||||
704 | void ScRangeName::UpdateReference(sc::RefUpdateContext& rCxt, SCTAB nLocalTab ) | |||
705 | { | |||
706 | if (rCxt.meMode == URM_COPY) | |||
707 | // Copying cells does not modify named expressions. | |||
708 | return; | |||
709 | ||||
710 | for (auto const& itr : m_Data) | |||
711 | { | |||
712 | itr.second->UpdateReference(rCxt, nLocalTab); | |||
713 | } | |||
714 | } | |||
715 | ||||
716 | void ScRangeName::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab ) | |||
717 | { | |||
718 | for (auto const& itr : m_Data) | |||
719 | { | |||
720 | itr.second->UpdateInsertTab(rCxt, nLocalTab); | |||
721 | } | |||
722 | } | |||
723 | ||||
724 | void ScRangeName::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab ) | |||
725 | { | |||
726 | for (auto const& itr : m_Data) | |||
727 | { | |||
728 | itr.second->UpdateDeleteTab(rCxt, nLocalTab); | |||
729 | } | |||
730 | } | |||
731 | ||||
732 | void ScRangeName::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab ) | |||
733 | { | |||
734 | for (auto const& itr : m_Data) | |||
735 | { | |||
736 | itr.second->UpdateMoveTab(rCxt, nLocalTab); | |||
737 | } | |||
738 | } | |||
739 | ||||
740 | void ScRangeName::UpdateTranspose(const ScRange& rSource, const ScAddress& rDest) | |||
741 | { | |||
742 | for (auto const& itr : m_Data) | |||
743 | { | |||
744 | itr.second->UpdateTranspose(rSource, rDest); | |||
745 | } | |||
746 | } | |||
747 | ||||
748 | void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) | |||
749 | { | |||
750 | for (auto const& itr : m_Data) | |||
751 | { | |||
752 | itr.second->UpdateGrow(rArea, nGrowX, nGrowY); | |||
753 | } | |||
754 | } | |||
755 | ||||
756 | void ScRangeName::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt ) | |||
757 | { | |||
758 | for (auto const& itr : m_Data) | |||
759 | { | |||
760 | itr.second->CompileUnresolvedXML(rCxt); | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | void ScRangeName::CopyUsedNames( const SCTAB nLocalTab, const SCTAB nOldTab, const SCTAB nNewTab, | |||
765 | const ScDocument& rOldDoc, ScDocument& rNewDoc, const bool bGlobalNamesToLocal ) const | |||
766 | { | |||
767 | for (auto const& itr : m_Data) | |||
768 | { | |||
769 | SCTAB nSheet = (nLocalTab < 0) ? nLocalTab : nOldTab; | |||
770 | sal_uInt16 nIndex = itr.second->GetIndex(); | |||
771 | ScAddress aOldPos( itr.second->GetPos()); | |||
772 | aOldPos.SetTab( nOldTab); | |||
773 | ScAddress aNewPos( aOldPos); | |||
774 | aNewPos.SetTab( nNewTab); | |||
775 | ScRangeData* pRangeData = nullptr; | |||
776 | rOldDoc.CopyAdjustRangeName( nSheet, nIndex, pRangeData, rNewDoc, aNewPos, aOldPos, bGlobalNamesToLocal, false); | |||
777 | } | |||
778 | } | |||
779 | ||||
780 | ScRangeName::const_iterator ScRangeName::begin() const | |||
781 | { | |||
782 | return m_Data.begin(); | |||
783 | } | |||
784 | ||||
785 | ScRangeName::const_iterator ScRangeName::end() const | |||
786 | { | |||
787 | return m_Data.end(); | |||
788 | } | |||
789 | ||||
790 | ScRangeName::iterator ScRangeName::begin() | |||
791 | { | |||
792 | return m_Data.begin(); | |||
793 | } | |||
794 | ||||
795 | ScRangeName::iterator ScRangeName::end() | |||
796 | { | |||
797 | return m_Data.end(); | |||
798 | } | |||
799 | ||||
800 | size_t ScRangeName::size() const | |||
801 | { | |||
802 | return m_Data.size(); | |||
803 | } | |||
804 | ||||
805 | bool ScRangeName::empty() const | |||
806 | { | |||
807 | return m_Data.empty(); | |||
808 | } | |||
809 | ||||
810 | bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex ) | |||
811 | { | |||
812 | if (!p) | |||
813 | return false; | |||
814 | ||||
815 | if (!p->GetIndex()) | |||
816 | { | |||
817 | // Assign a new index. An index must be unique and is never 0. | |||
818 | if (bReuseFreeIndex) | |||
819 | { | |||
820 | IndexDataType::iterator itr = std::find( | |||
821 | maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(nullptr)); | |||
822 | if (itr != maIndexToData.end()) | |||
823 | { | |||
824 | // Empty slot exists. Re-use it. | |||
825 | size_t nPos = std::distance(maIndexToData.begin(), itr); | |||
826 | p->SetIndex(nPos + 1); | |||
827 | } | |||
828 | else | |||
829 | // No empty slot. Append it to the end. | |||
830 | p->SetIndex(maIndexToData.size() + 1); | |||
831 | } | |||
832 | else | |||
833 | { | |||
834 | p->SetIndex(maIndexToData.size() + 1); | |||
835 | } | |||
836 | } | |||
837 | ||||
838 | OUString aName(p->GetUpperName()); | |||
839 | erase(aName); // ptr_map won't insert it if a duplicate name exists. | |||
840 | pair<DataType::iterator, bool> r = | |||
841 | m_Data.insert(std::make_pair(aName, std::unique_ptr<ScRangeData>(p))); | |||
842 | if (r.second) | |||
843 | { | |||
844 | // Data inserted. Store its index for mapping. | |||
845 | size_t nPos = p->GetIndex() - 1; | |||
846 | if (nPos >= maIndexToData.size()) | |||
847 | maIndexToData.resize(nPos+1, nullptr); | |||
848 | maIndexToData[nPos] = p; | |||
849 | } | |||
850 | return r.second; | |||
851 | } | |||
852 | ||||
853 | void ScRangeName::erase(const ScRangeData& r) | |||
854 | { | |||
855 | erase(r.GetUpperName()); | |||
856 | } | |||
857 | ||||
858 | void ScRangeName::erase(const OUString& rName) | |||
859 | { | |||
860 | DataType::iterator itr = m_Data.find(rName); | |||
861 | if (itr != m_Data.end()) | |||
862 | erase(itr); | |||
863 | } | |||
864 | ||||
865 | void ScRangeName::erase(const iterator& itr) | |||
866 | { | |||
867 | sal_uInt16 nIndex = itr->second->GetIndex(); | |||
868 | m_Data.erase(itr); | |||
869 | OSL_ENSURE( 0 < nIndex && nIndex <= maIndexToData.size(), "ScRangeName::erase: bad index")do { if (true && (!(0 < nIndex && nIndex <= maIndexToData.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/rangenam.cxx" ":" "869" ": "), "%s", "ScRangeName::erase: bad index"); } } while (false); | |||
870 | if (0 < nIndex && nIndex <= maIndexToData.size()) | |||
871 | maIndexToData[nIndex-1] = nullptr; | |||
872 | } | |||
873 | ||||
874 | void ScRangeName::clear() | |||
875 | { | |||
876 | m_Data.clear(); | |||
877 | maIndexToData.clear(); | |||
878 | } | |||
879 | ||||
880 | bool ScRangeName::operator== (const ScRangeName& r) const | |||
881 | { | |||
882 | return std::equal(m_Data.begin(), m_Data.end(), r.m_Data.begin(), r.m_Data.end(), | |||
883 | [](const DataType::value_type& lhs, const DataType::value_type& rhs) { | |||
884 | return (lhs.first == rhs.first) && (*lhs.second == *rhs.second); | |||
885 | }); | |||
886 | } | |||
887 | ||||
888 | /* 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 */ |