File: | home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx |
Warning: | line 484, column 25 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||||||||||
2 | /* | ||||||||||||
3 | * This file is part of the LibreOffice project. | ||||||||||||
4 | * | ||||||||||||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | ||||||||||||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||||||||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||||||||
8 | * | ||||||||||||
9 | * This file incorporates work covered by the following license notice: | ||||||||||||
10 | * | ||||||||||||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | ||||||||||||
12 | * contributor license agreements. See the NOTICE file distributed | ||||||||||||
13 | * with this work for additional information regarding copyright | ||||||||||||
14 | * ownership. The ASF licenses this file to you under the Apache | ||||||||||||
15 | * License, Version 2.0 (the "License"); you may not use this file | ||||||||||||
16 | * except in compliance with the License. You may obtain a copy of | ||||||||||||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | ||||||||||||
18 | */ | ||||||||||||
19 | |||||||||||||
20 | #include <vector> | ||||||||||||
21 | #include <unordered_set> | ||||||||||||
22 | #include <editeng/editdata.hxx> | ||||||||||||
23 | #include <rtl/strbuf.hxx> | ||||||||||||
24 | #include <svx/xfillit0.hxx> | ||||||||||||
25 | #include <svx/xlineit0.hxx> | ||||||||||||
26 | #include <svx/svdxcgv.hxx> | ||||||||||||
27 | #include <svx/svdoutl.hxx> | ||||||||||||
28 | #include <svx/svdundo.hxx> | ||||||||||||
29 | #include <svx/svdograf.hxx> | ||||||||||||
30 | #include <svx/svdoole2.hxx> | ||||||||||||
31 | #include <svx/svdorect.hxx> | ||||||||||||
32 | #include <svx/svdopage.hxx> | ||||||||||||
33 | #include <svx/svdpage.hxx> | ||||||||||||
34 | #include <svx/svdpagv.hxx> | ||||||||||||
35 | #include <svx/svdtrans.hxx> | ||||||||||||
36 | #include <svx/strings.hrc> | ||||||||||||
37 | #include <svx/dialmgr.hxx> | ||||||||||||
38 | #include <tools/bigint.hxx> | ||||||||||||
39 | #include <clonelist.hxx> | ||||||||||||
40 | #include <vcl/virdev.hxx> | ||||||||||||
41 | #include <svl/style.hxx> | ||||||||||||
42 | #include <fmobj.hxx> | ||||||||||||
43 | #include <vcl/vectorgraphicdata.hxx> | ||||||||||||
44 | #include <drawinglayer/primitive2d/groupprimitive2d.hxx> | ||||||||||||
45 | #include <drawinglayer/geometry/viewinformation2d.hxx> | ||||||||||||
46 | #include <svx/sdr/contact/viewcontact.hxx> | ||||||||||||
47 | #include <sdr/contact/objectcontactofobjlistpainter.hxx> | ||||||||||||
48 | #include <svx/sdr/contact/displayinfo.hxx> | ||||||||||||
49 | #include <svx/svdotable.hxx> | ||||||||||||
50 | #include <sal/log.hxx> | ||||||||||||
51 | |||||||||||||
52 | using namespace com::sun::star; | ||||||||||||
53 | |||||||||||||
54 | SdrExchangeView::SdrExchangeView( | ||||||||||||
55 | SdrModel& rSdrModel, | ||||||||||||
56 | OutputDevice* pOut) | ||||||||||||
57 | : SdrObjEditView(rSdrModel, pOut) | ||||||||||||
58 | { | ||||||||||||
59 | } | ||||||||||||
60 | |||||||||||||
61 | bool SdrExchangeView::ImpLimitToWorkArea(Point& rPt) const | ||||||||||||
62 | { | ||||||||||||
63 | bool bRet(false); | ||||||||||||
64 | |||||||||||||
65 | if(!maMaxWorkArea.IsEmpty()) | ||||||||||||
66 | { | ||||||||||||
67 | if(rPt.X()<maMaxWorkArea.Left()) | ||||||||||||
68 | { | ||||||||||||
69 | rPt.setX( maMaxWorkArea.Left() ); | ||||||||||||
70 | bRet = true; | ||||||||||||
71 | } | ||||||||||||
72 | |||||||||||||
73 | if(rPt.X()>maMaxWorkArea.Right()) | ||||||||||||
74 | { | ||||||||||||
75 | rPt.setX( maMaxWorkArea.Right() ); | ||||||||||||
76 | bRet = true; | ||||||||||||
77 | } | ||||||||||||
78 | |||||||||||||
79 | if(rPt.Y()<maMaxWorkArea.Top()) | ||||||||||||
80 | { | ||||||||||||
81 | rPt.setY( maMaxWorkArea.Top() ); | ||||||||||||
82 | bRet = true; | ||||||||||||
83 | } | ||||||||||||
84 | |||||||||||||
85 | if(rPt.Y()>maMaxWorkArea.Bottom()) | ||||||||||||
86 | { | ||||||||||||
87 | rPt.setY( maMaxWorkArea.Bottom() ); | ||||||||||||
88 | bRet = true; | ||||||||||||
89 | } | ||||||||||||
90 | } | ||||||||||||
91 | return bRet; | ||||||||||||
92 | } | ||||||||||||
93 | |||||||||||||
94 | void SdrExchangeView::ImpGetPasteObjList(Point& /*rPos*/, SdrObjList*& rpLst) | ||||||||||||
95 | { | ||||||||||||
96 | if (rpLst==nullptr) | ||||||||||||
97 | { | ||||||||||||
98 | SdrPageView* pPV = GetSdrPageView(); | ||||||||||||
99 | |||||||||||||
100 | if (pPV!=nullptr) { | ||||||||||||
101 | rpLst=pPV->GetObjList(); | ||||||||||||
102 | } | ||||||||||||
103 | } | ||||||||||||
104 | } | ||||||||||||
105 | |||||||||||||
106 | bool SdrExchangeView::ImpGetPasteLayer(const SdrObjList* pObjList, SdrLayerID& rLayer) const | ||||||||||||
107 | { | ||||||||||||
108 | bool bRet=false; | ||||||||||||
109 | rLayer=SdrLayerID(0); | ||||||||||||
110 | if (pObjList!=nullptr) { | ||||||||||||
111 | const SdrPage* pPg=pObjList->getSdrPageFromSdrObjList(); | ||||||||||||
112 | if (pPg!=nullptr) { | ||||||||||||
113 | rLayer=pPg->GetLayerAdmin().GetLayerID(maActualLayer); | ||||||||||||
114 | if (rLayer==SDRLAYER_NOTFOUND) rLayer=SdrLayerID(0); | ||||||||||||
115 | SdrPageView* pPV = GetSdrPageView(); | ||||||||||||
116 | if (pPV!=nullptr) { | ||||||||||||
117 | bRet=!pPV->GetLockedLayers().IsSet(rLayer) && pPV->GetVisibleLayers().IsSet(rLayer); | ||||||||||||
118 | } | ||||||||||||
119 | } | ||||||||||||
120 | } | ||||||||||||
121 | return bRet; | ||||||||||||
122 | } | ||||||||||||
123 | |||||||||||||
124 | bool SdrExchangeView::Paste(const OUString& rStr, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) | ||||||||||||
125 | { | ||||||||||||
126 | if (rStr.isEmpty()) | ||||||||||||
127 | return false; | ||||||||||||
128 | |||||||||||||
129 | Point aPos(rPos); | ||||||||||||
130 | ImpGetPasteObjList(aPos,pLst); | ||||||||||||
131 | ImpLimitToWorkArea( aPos ); | ||||||||||||
132 | if (pLst==nullptr) return false; | ||||||||||||
133 | SdrLayerID nLayer; | ||||||||||||
134 | if (!ImpGetPasteLayer(pLst,nLayer)) return false; | ||||||||||||
135 | bool bUnmark = (nOptions & (SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); | ||||||||||||
136 | if (bUnmark) UnmarkAllObj(); | ||||||||||||
137 | tools::Rectangle aTextRect(0,0,500,500); | ||||||||||||
138 | SdrPage* pPage=pLst->getSdrPageFromSdrObjList(); | ||||||||||||
139 | if (pPage!=nullptr) { | ||||||||||||
140 | aTextRect.SetSize(pPage->GetSize()); | ||||||||||||
141 | } | ||||||||||||
142 | SdrRectObj* pObj = new SdrRectObj( | ||||||||||||
143 | getSdrModelFromSdrView(), | ||||||||||||
144 | OBJ_TEXT, | ||||||||||||
145 | aTextRect); | ||||||||||||
146 | |||||||||||||
147 | pObj->SetLayer(nLayer); | ||||||||||||
148 | pObj->NbcSetText(rStr); // SetText before SetAttr, else SetAttr doesn't work! | ||||||||||||
149 | if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false); | ||||||||||||
150 | |||||||||||||
151 | pObj->SetMergedItemSet(maDefaultAttr); | ||||||||||||
152 | |||||||||||||
153 | SfxItemSet aTempAttr(mpModel->GetItemPool()); // no fill, no line | ||||||||||||
154 | aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE)); | ||||||||||||
155 | aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE)); | ||||||||||||
156 | |||||||||||||
157 | pObj->SetMergedItemSet(aTempAttr); | ||||||||||||
158 | |||||||||||||
159 | pObj->FitFrameToTextSize(); | ||||||||||||
160 | Size aSiz(pObj->GetLogicRect().GetSize()); | ||||||||||||
161 | MapUnit eMap=mpModel->GetScaleUnit(); | ||||||||||||
162 | Fraction aMap=mpModel->GetScaleFraction(); | ||||||||||||
163 | ImpPasteObject(pObj,*pLst,aPos,aSiz,MapMode(eMap,Point(0,0),aMap,aMap),nOptions); | ||||||||||||
164 | return true; | ||||||||||||
165 | } | ||||||||||||
166 | |||||||||||||
167 | bool SdrExchangeView::Paste(SvStream& rInput, EETextFormat eFormat, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) | ||||||||||||
168 | { | ||||||||||||
169 | Point aPos(rPos); | ||||||||||||
170 | ImpGetPasteObjList(aPos,pLst); | ||||||||||||
171 | ImpLimitToWorkArea( aPos ); | ||||||||||||
172 | if (pLst==nullptr) return false; | ||||||||||||
173 | SdrLayerID nLayer; | ||||||||||||
174 | if (!ImpGetPasteLayer(pLst,nLayer)) return false; | ||||||||||||
175 | bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); | ||||||||||||
176 | if (bUnmark) UnmarkAllObj(); | ||||||||||||
177 | tools::Rectangle aTextRect(0,0,500,500); | ||||||||||||
178 | SdrPage* pPage=pLst->getSdrPageFromSdrObjList(); | ||||||||||||
179 | if (pPage!=nullptr) { | ||||||||||||
180 | aTextRect.SetSize(pPage->GetSize()); | ||||||||||||
181 | } | ||||||||||||
182 | SdrRectObj* pObj = new SdrRectObj( | ||||||||||||
183 | getSdrModelFromSdrView(), | ||||||||||||
184 | OBJ_TEXT, | ||||||||||||
185 | aTextRect); | ||||||||||||
186 | |||||||||||||
187 | pObj->SetLayer(nLayer); | ||||||||||||
188 | if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false); | ||||||||||||
189 | |||||||||||||
190 | pObj->SetMergedItemSet(maDefaultAttr); | ||||||||||||
191 | |||||||||||||
192 | SfxItemSet aTempAttr(mpModel->GetItemPool()); // no fill, no line | ||||||||||||
193 | aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE)); | ||||||||||||
194 | aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE)); | ||||||||||||
195 | |||||||||||||
196 | pObj->SetMergedItemSet(aTempAttr); | ||||||||||||
197 | |||||||||||||
198 | pObj->NbcSetText(rInput,OUString(),eFormat); | ||||||||||||
199 | pObj->FitFrameToTextSize(); | ||||||||||||
200 | Size aSiz(pObj->GetLogicRect().GetSize()); | ||||||||||||
201 | MapUnit eMap=mpModel->GetScaleUnit(); | ||||||||||||
202 | Fraction aMap=mpModel->GetScaleFraction(); | ||||||||||||
203 | ImpPasteObject(pObj,*pLst,aPos,aSiz,MapMode(eMap,Point(0,0),aMap,aMap),nOptions); | ||||||||||||
204 | |||||||||||||
205 | // b4967543 | ||||||||||||
206 | if(pObj->GetOutlinerParaObject()) | ||||||||||||
207 | { | ||||||||||||
208 | SdrOutliner& rOutliner = pObj->getSdrModelFromSdrObject().GetHitTestOutliner(); | ||||||||||||
209 | rOutliner.SetText(*pObj->GetOutlinerParaObject()); | ||||||||||||
210 | |||||||||||||
211 | if(1 == rOutliner.GetParagraphCount()) | ||||||||||||
212 | { | ||||||||||||
213 | SfxStyleSheet* pCandidate = rOutliner.GetStyleSheet(0); | ||||||||||||
214 | |||||||||||||
215 | if(pCandidate) | ||||||||||||
216 | { | ||||||||||||
217 | if(pObj->getSdrModelFromSdrObject().GetStyleSheetPool() == pCandidate->GetPool()) | ||||||||||||
218 | { | ||||||||||||
219 | pObj->NbcSetStyleSheet(pCandidate, true); | ||||||||||||
220 | } | ||||||||||||
221 | } | ||||||||||||
222 | } | ||||||||||||
223 | } | ||||||||||||
224 | |||||||||||||
225 | return true; | ||||||||||||
226 | } | ||||||||||||
227 | |||||||||||||
228 | bool SdrExchangeView::Paste( | ||||||||||||
229 | const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) | ||||||||||||
230 | { | ||||||||||||
231 | const SdrModel* pSrcMod=&rMod; | ||||||||||||
232 | if (pSrcMod==mpModel) | ||||||||||||
233 | return false; // this can't work, right? | ||||||||||||
234 | |||||||||||||
235 | const bool bUndo = IsUndoEnabled(); | ||||||||||||
236 | |||||||||||||
237 | if( bUndo ) | ||||||||||||
238 | BegUndo(SvxResId(STR_ExchangePastereinterpret_cast<char const *>("STR_ExchangePaste" "\004" u8"Insert object(s)"))); | ||||||||||||
239 | |||||||||||||
240 | if( mxSelectionController.is() && mxSelectionController->PasteObjModel( rMod ) ) | ||||||||||||
241 | { | ||||||||||||
242 | if( bUndo ) | ||||||||||||
243 | EndUndo(); | ||||||||||||
244 | return true; | ||||||||||||
245 | } | ||||||||||||
246 | |||||||||||||
247 | Point aPos(rPos); | ||||||||||||
248 | ImpGetPasteObjList(aPos,pLst); | ||||||||||||
249 | SdrPageView* pMarkPV=nullptr; | ||||||||||||
250 | SdrPageView* pPV = GetSdrPageView(); | ||||||||||||
251 | |||||||||||||
252 | if(pPV && pPV->GetObjList() == pLst ) | ||||||||||||
253 | pMarkPV=pPV; | ||||||||||||
254 | |||||||||||||
255 | ImpLimitToWorkArea( aPos ); | ||||||||||||
256 | if (pLst==nullptr) | ||||||||||||
257 | return false; | ||||||||||||
258 | |||||||||||||
259 | bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); | ||||||||||||
260 | if (bUnmark) | ||||||||||||
261 | UnmarkAllObj(); | ||||||||||||
262 | |||||||||||||
263 | // Rescale, if the Model uses a different MapUnit. | ||||||||||||
264 | // Calculate the necessary factors first. | ||||||||||||
265 | MapUnit eSrcUnit=pSrcMod->GetScaleUnit(); | ||||||||||||
266 | MapUnit eDstUnit=mpModel->GetScaleUnit(); | ||||||||||||
267 | bool bResize=eSrcUnit!=eDstUnit; | ||||||||||||
268 | Fraction aXResize,aYResize; | ||||||||||||
269 | Point aPt0; | ||||||||||||
270 | if (bResize) | ||||||||||||
271 | { | ||||||||||||
272 | FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit)); | ||||||||||||
273 | aXResize=aResize.X(); | ||||||||||||
274 | aYResize=aResize.Y(); | ||||||||||||
275 | } | ||||||||||||
276 | SdrObjList* pDstLst=pLst; | ||||||||||||
277 | sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount(); | ||||||||||||
278 | for (nPg=0; nPg<nPgCount; nPg++) | ||||||||||||
279 | { | ||||||||||||
280 | const SdrPage* pSrcPg=pSrcMod->GetPage(nPg); | ||||||||||||
281 | |||||||||||||
282 | // Use SnapRect, not BoundRect here | ||||||||||||
283 | tools::Rectangle aR=pSrcPg->GetAllObjSnapRect(); | ||||||||||||
284 | |||||||||||||
285 | if (bResize) | ||||||||||||
286 | ResizeRect(aR,aPt0,aXResize,aYResize); | ||||||||||||
287 | Point aDist(aPos-aR.Center()); | ||||||||||||
288 | Size aSiz(aDist.X(),aDist.Y()); | ||||||||||||
289 | size_t nCloneErrCnt = 0; | ||||||||||||
290 | const size_t nObjCount = pSrcPg->GetObjCount(); | ||||||||||||
291 | bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE; | ||||||||||||
292 | |||||||||||||
293 | // #i13033# | ||||||||||||
294 | // New mechanism to re-create the connections of cloned connectors | ||||||||||||
295 | CloneList aCloneList; | ||||||||||||
296 | std::unordered_set<rtl::OUString> aNameSet; | ||||||||||||
297 | for (size_t nOb=0; nOb<nObjCount; ++nOb) | ||||||||||||
298 | { | ||||||||||||
299 | const SdrObject* pSrcOb=pSrcPg->GetObj(nOb); | ||||||||||||
300 | |||||||||||||
301 | SdrObject* pNewObj(pSrcOb->CloneSdrObject(*mpModel)); | ||||||||||||
302 | |||||||||||||
303 | if (pNewObj!=nullptr) | ||||||||||||
304 | { | ||||||||||||
305 | if(bResize) | ||||||||||||
306 | { | ||||||||||||
307 | pNewObj->getSdrModelFromSdrObject().SetPasteResize(true); | ||||||||||||
308 | pNewObj->NbcResize(aPt0,aXResize,aYResize); | ||||||||||||
309 | pNewObj->getSdrModelFromSdrObject().SetPasteResize(false); | ||||||||||||
310 | } | ||||||||||||
311 | |||||||||||||
312 | // #i39861# | ||||||||||||
313 | pNewObj->NbcMove(aSiz); | ||||||||||||
314 | |||||||||||||
315 | const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList(); | ||||||||||||
316 | |||||||||||||
317 | if(pPg) | ||||||||||||
318 | { | ||||||||||||
319 | // #i72535# | ||||||||||||
320 | const SdrLayerAdmin& rAd = pPg->GetLayerAdmin(); | ||||||||||||
321 | SdrLayerID nLayer(0); | ||||||||||||
322 | |||||||||||||
323 | if(dynamic_cast<const FmFormObj*>( pNewObj) != nullptr) | ||||||||||||
324 | { | ||||||||||||
325 | // for FormControls, force to form layer | ||||||||||||
326 | nLayer = rAd.GetLayerID(rAd.GetControlLayerName()); | ||||||||||||
327 | } | ||||||||||||
328 | else | ||||||||||||
329 | { | ||||||||||||
330 | nLayer = rAd.GetLayerID(maActualLayer); | ||||||||||||
331 | } | ||||||||||||
332 | |||||||||||||
333 | if(SDRLAYER_NOTFOUND == nLayer) | ||||||||||||
334 | { | ||||||||||||
335 | nLayer = SdrLayerID(0); | ||||||||||||
336 | } | ||||||||||||
337 | |||||||||||||
338 | pNewObj->SetLayer(nLayer); | ||||||||||||
339 | } | ||||||||||||
340 | |||||||||||||
341 | pDstLst->InsertObjectThenMakeNameUnique(pNewObj, aNameSet); | ||||||||||||
342 | |||||||||||||
343 | if( bUndo ) | ||||||||||||
344 | AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj)); | ||||||||||||
345 | |||||||||||||
346 | if (bMark) { | ||||||||||||
347 | // Don't already set Markhandles! | ||||||||||||
348 | // That is instead being done by ModelHasChanged in MarkView. | ||||||||||||
349 | MarkObj(pNewObj,pMarkPV,false,true); | ||||||||||||
350 | } | ||||||||||||
351 | |||||||||||||
352 | // #i13033# | ||||||||||||
353 | aCloneList.AddPair(pSrcOb, pNewObj); | ||||||||||||
354 | } | ||||||||||||
355 | else | ||||||||||||
356 | { | ||||||||||||
357 | nCloneErrCnt++; | ||||||||||||
358 | } | ||||||||||||
359 | } | ||||||||||||
360 | |||||||||||||
361 | // #i13033# | ||||||||||||
362 | // New mechanism to re-create the connections of cloned connectors | ||||||||||||
363 | aCloneList.CopyConnections(); | ||||||||||||
364 | |||||||||||||
365 | if(0 != nCloneErrCnt) | ||||||||||||
366 | { | ||||||||||||
367 | #ifdef DBG_UTIL | ||||||||||||
368 | OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning "); | ||||||||||||
369 | |||||||||||||
370 | if(nCloneErrCnt == 1) | ||||||||||||
371 | { | ||||||||||||
372 | aStr.append("a drawing object."); | ||||||||||||
373 | } | ||||||||||||
374 | else | ||||||||||||
375 | { | ||||||||||||
376 | aStr.append(static_cast<sal_Int32>(nCloneErrCnt)); | ||||||||||||
377 | aStr.append(" drawing objects."); | ||||||||||||
378 | } | ||||||||||||
379 | |||||||||||||
380 | aStr.append(" Not copying object connectors."); | ||||||||||||
381 | |||||||||||||
382 | OSL_FAIL(aStr.getStr())do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx" ":" "382" ": "), "%s", aStr.getStr()); } } while (false); | ||||||||||||
383 | #endif | ||||||||||||
384 | } | ||||||||||||
385 | } | ||||||||||||
386 | |||||||||||||
387 | if( bUndo ) | ||||||||||||
388 | EndUndo(); | ||||||||||||
389 | |||||||||||||
390 | return true; | ||||||||||||
391 | } | ||||||||||||
392 | |||||||||||||
393 | void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions) | ||||||||||||
394 | { | ||||||||||||
395 | BigInt nSizX(rSiz.Width()); | ||||||||||||
396 | BigInt nSizY(rSiz.Height()); | ||||||||||||
397 | MapUnit eSrcMU=rMap.GetMapUnit(); | ||||||||||||
398 | MapUnit eDstMU=mpModel->GetScaleUnit(); | ||||||||||||
399 | FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU)); | ||||||||||||
400 | Fraction aDstFr(mpModel->GetScaleFraction()); | ||||||||||||
401 | nSizX *= double(aMapFact.X() * rMap.GetScaleX() * aDstFr); | ||||||||||||
402 | nSizX *= aDstFr.GetDenominator(); | ||||||||||||
403 | nSizY *= double(aMapFact.Y() * rMap.GetScaleY()); | ||||||||||||
404 | nSizY /= aDstFr.GetNumerator(); | ||||||||||||
405 | long xs=nSizX; | ||||||||||||
406 | long ys=nSizY; | ||||||||||||
407 | Point aPos(rCenter.X()-xs/2,rCenter.Y()-ys/2); | ||||||||||||
408 | tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys); | ||||||||||||
409 | pObj->SetLogicRect(aR); | ||||||||||||
410 | rLst.InsertObject(pObj, SAL_MAX_SIZE((sal_uInt64) 0xFFFFFFFFFFFFFFFFul)); | ||||||||||||
411 | |||||||||||||
412 | if( IsUndoEnabled() ) | ||||||||||||
413 | AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj)); | ||||||||||||
414 | |||||||||||||
415 | SdrPageView* pMarkPV=nullptr; | ||||||||||||
416 | SdrPageView* pPV = GetSdrPageView(); | ||||||||||||
417 | |||||||||||||
418 | if(pPV && pPV->GetObjList()==&rLst) | ||||||||||||
419 | pMarkPV=pPV; | ||||||||||||
420 | |||||||||||||
421 | bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE; | ||||||||||||
422 | if (bMark) | ||||||||||||
423 | { // select object the first PageView we found | ||||||||||||
424 | MarkObj(pObj,pMarkPV); | ||||||||||||
425 | } | ||||||||||||
426 | } | ||||||||||||
427 | |||||||||||||
428 | BitmapEx SdrExchangeView::GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked) const | ||||||||||||
429 | { | ||||||||||||
430 | BitmapEx aBmp; | ||||||||||||
431 | |||||||||||||
432 | if( AreObjectsMarked() ) | ||||||||||||
| |||||||||||||
433 | { | ||||||||||||
434 | if(1 == GetMarkedObjectCount()) | ||||||||||||
435 | { | ||||||||||||
436 | if(bNoVDevIfOneBmpMarked) | ||||||||||||
437 | { | ||||||||||||
438 | SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 ); | ||||||||||||
439 | SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>( pGrafObjTmp ); | ||||||||||||
440 | |||||||||||||
441 | if( pGrafObj && ( pGrafObj->GetGraphicType() == GraphicType::Bitmap ) ) | ||||||||||||
442 | { | ||||||||||||
443 | aBmp = pGrafObj->GetTransformedGraphic().GetBitmapEx(); | ||||||||||||
444 | } | ||||||||||||
445 | } | ||||||||||||
446 | else | ||||||||||||
447 | { | ||||||||||||
448 | const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(GetMarkedObjectByIndex(0)); | ||||||||||||
449 | |||||||||||||
450 | if(pSdrGrafObj && pSdrGrafObj->isEmbeddedVectorGraphicData()) | ||||||||||||
451 | { | ||||||||||||
452 | aBmp = pSdrGrafObj->GetGraphic().getVectorGraphicData()->getReplacement(); | ||||||||||||
453 | } | ||||||||||||
454 | } | ||||||||||||
455 | } | ||||||||||||
456 | |||||||||||||
457 | if( !aBmp ) | ||||||||||||
458 | { | ||||||||||||
459 | // choose conversion directly using primitives to bitmap to avoid | ||||||||||||
460 | // rendering errors with tiled bitmap fills (these will be tiled in a | ||||||||||||
461 | // in-between metafile, but tend to show 'gaps' since the target is *no* | ||||||||||||
462 | // bitmap rendering) | ||||||||||||
463 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); | ||||||||||||
464 | const sal_uInt32 nCount(aSdrObjects.size()); | ||||||||||||
465 | |||||||||||||
466 | if(nCount) | ||||||||||||
467 | { | ||||||||||||
468 | // collect sub-primitives as group objects, thus no expensive append | ||||||||||||
469 | // to existing sequence is needed | ||||||||||||
470 | drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount); | ||||||||||||
471 | |||||||||||||
472 | for(sal_uInt32 a(0); a
| ||||||||||||
473 | { | ||||||||||||
474 | SdrObject* pCandidate = aSdrObjects[a]; | ||||||||||||
475 | SdrGrafObj* pSdrGrafObj = dynamic_cast< SdrGrafObj* >(pCandidate); | ||||||||||||
476 | |||||||||||||
477 | if(pSdrGrafObj) | ||||||||||||
478 | { | ||||||||||||
479 | // #122753# To ensure existence of graphic content, force swap in | ||||||||||||
480 | pSdrGrafObj->ForceSwapIn(); | ||||||||||||
481 | } | ||||||||||||
482 | |||||||||||||
483 | xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D( | ||||||||||||
484 | pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer()); | ||||||||||||
| |||||||||||||
485 | } | ||||||||||||
486 | |||||||||||||
487 | // get logic range | ||||||||||||
488 | const drawinglayer::geometry::ViewInformation2D aViewInformation2D; | ||||||||||||
489 | const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D)); | ||||||||||||
490 | |||||||||||||
491 | if(!aRange.isEmpty()) | ||||||||||||
492 | { | ||||||||||||
493 | // if we have geometry and it has a range, convert to BitmapEx using | ||||||||||||
494 | // common tooling | ||||||||||||
495 | aBmp = convertPrimitive2DSequenceToBitmapEx( | ||||||||||||
496 | xPrimitives, | ||||||||||||
497 | aRange); | ||||||||||||
498 | } | ||||||||||||
499 | } | ||||||||||||
500 | } | ||||||||||||
501 | } | ||||||||||||
502 | |||||||||||||
503 | return aBmp; | ||||||||||||
504 | } | ||||||||||||
505 | |||||||||||||
506 | |||||||||||||
507 | GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const | ||||||||||||
508 | { | ||||||||||||
509 | GDIMetaFile aMtf; | ||||||||||||
510 | |||||||||||||
511 | if( AreObjectsMarked() ) | ||||||||||||
512 | { | ||||||||||||
513 | tools::Rectangle aBound( GetMarkedObjBoundRect() ); | ||||||||||||
514 | Size aBoundSize( aBound.GetWidth(), aBound.GetHeight() ); | ||||||||||||
515 | MapMode aMap( mpModel->GetScaleUnit(), Point(), mpModel->GetScaleFraction(), mpModel->GetScaleFraction() ); | ||||||||||||
516 | |||||||||||||
517 | if( bNoVDevIfOneMtfMarked ) | ||||||||||||
518 | { | ||||||||||||
519 | SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 ); | ||||||||||||
520 | SdrGrafObj* pGrafObj = ( GetMarkedObjectCount() ==1 ) ? dynamic_cast<SdrGrafObj*>( pGrafObjTmp ) : nullptr; | ||||||||||||
521 | |||||||||||||
522 | if( pGrafObj ) | ||||||||||||
523 | { | ||||||||||||
524 | Graphic aGraphic( pGrafObj->GetTransformedGraphic() ); | ||||||||||||
525 | |||||||||||||
526 | // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically | ||||||||||||
527 | aMtf = aGraphic.GetGDIMetaFile(); | ||||||||||||
528 | } | ||||||||||||
529 | } | ||||||||||||
530 | |||||||||||||
531 | if( !aMtf.GetActionSize() ) | ||||||||||||
532 | { | ||||||||||||
533 | ScopedVclPtrInstance< VirtualDevice > pOut; | ||||||||||||
534 | const Size aDummySize(2, 2); | ||||||||||||
535 | |||||||||||||
536 | pOut->SetOutputSizePixel(aDummySize); | ||||||||||||
537 | pOut->EnableOutput(false); | ||||||||||||
538 | pOut->SetMapMode(aMap); | ||||||||||||
539 | aMtf.Clear(); | ||||||||||||
540 | aMtf.Record(pOut); | ||||||||||||
541 | |||||||||||||
542 | DrawMarkedObj(*pOut); | ||||||||||||
543 | |||||||||||||
544 | aMtf.Stop(); | ||||||||||||
545 | aMtf.WindStart(); | ||||||||||||
546 | |||||||||||||
547 | // moving the result is more reliable then setting a relative MapMode at the VDev (used | ||||||||||||
548 | // before), also see #i99268# in GetObjGraphic() below. Some draw actions at | ||||||||||||
549 | // the OutDev are simply not handled correctly when a MapMode is set at the | ||||||||||||
550 | // target device, e.g. MetaFloatTransparentAction. Even the Move for this action | ||||||||||||
551 | // was missing the manipulation of the embedded Metafile | ||||||||||||
552 | aMtf.Move(-aBound.Left(), -aBound.Top()); | ||||||||||||
553 | |||||||||||||
554 | aMtf.SetPrefMapMode( aMap ); | ||||||||||||
555 | |||||||||||||
556 | // removed PrefSize extension. It is principally wrong to set a reduced size at | ||||||||||||
557 | // the created MetaFile. The mentioned errors occur at output time since the integer | ||||||||||||
558 | // MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for | ||||||||||||
559 | // primitives (and may later be done in breaking up a MetaFile to primitives) | ||||||||||||
560 | aMtf.SetPrefSize(aBoundSize); | ||||||||||||
561 | } | ||||||||||||
562 | } | ||||||||||||
563 | |||||||||||||
564 | return aMtf; | ||||||||||||
565 | } | ||||||||||||
566 | |||||||||||||
567 | |||||||||||||
568 | Graphic SdrExchangeView::GetAllMarkedGraphic() const | ||||||||||||
569 | { | ||||||||||||
570 | Graphic aRet; | ||||||||||||
571 | |||||||||||||
572 | if( AreObjectsMarked() ) | ||||||||||||
573 | { | ||||||||||||
574 | if( ( 1 == GetMarkedObjectCount() ) && GetSdrMarkByIndex( 0 ) ) | ||||||||||||
575 | aRet = SdrExchangeView::GetObjGraphic(*GetMarkedObjectByIndex(0)); | ||||||||||||
576 | else | ||||||||||||
577 | aRet = GetMarkedObjMetaFile(); | ||||||||||||
578 | } | ||||||||||||
579 | |||||||||||||
580 | return aRet; | ||||||||||||
581 | } | ||||||||||||
582 | |||||||||||||
583 | |||||||||||||
584 | Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject) | ||||||||||||
585 | { | ||||||||||||
586 | Graphic aRet; | ||||||||||||
587 | |||||||||||||
588 | // try to get a graphic from the object first | ||||||||||||
589 | const SdrGrafObj* pSdrGrafObj(dynamic_cast< const SdrGrafObj* >(&rSdrObject)); | ||||||||||||
590 | const SdrOle2Obj* pSdrOle2Obj(dynamic_cast< const SdrOle2Obj* >(&rSdrObject)); | ||||||||||||
591 | |||||||||||||
592 | if(pSdrGrafObj) | ||||||||||||
593 | { | ||||||||||||
594 | if(pSdrGrafObj->isEmbeddedVectorGraphicData()) | ||||||||||||
595 | { | ||||||||||||
596 | // get Metafile for Svg content | ||||||||||||
597 | aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData(); | ||||||||||||
598 | } | ||||||||||||
599 | else | ||||||||||||
600 | { | ||||||||||||
601 | // Make behaviour coherent with metafile | ||||||||||||
602 | // recording below (which of course also takes | ||||||||||||
603 | // view-transformed objects) | ||||||||||||
604 | aRet = pSdrGrafObj->GetTransformedGraphic(); | ||||||||||||
605 | } | ||||||||||||
606 | } | ||||||||||||
607 | else if(pSdrOle2Obj) | ||||||||||||
608 | { | ||||||||||||
609 | if(pSdrOle2Obj->GetGraphic()) | ||||||||||||
610 | { | ||||||||||||
611 | aRet = *pSdrOle2Obj->GetGraphic(); | ||||||||||||
612 | } | ||||||||||||
613 | } | ||||||||||||
614 | |||||||||||||
615 | // if graphic could not be retrieved => go the hard way and create a MetaFile | ||||||||||||
616 | if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType())) | ||||||||||||
617 | { | ||||||||||||
618 | ScopedVclPtrInstance< VirtualDevice > pOut; | ||||||||||||
619 | GDIMetaFile aMtf; | ||||||||||||
620 | const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect()); | ||||||||||||
621 | const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit(), | ||||||||||||
622 | Point(), | ||||||||||||
623 | rSdrObject.getSdrModelFromSdrObject().GetScaleFraction(), | ||||||||||||
624 | rSdrObject.getSdrModelFromSdrObject().GetScaleFraction()); | ||||||||||||
625 | |||||||||||||
626 | pOut->EnableOutput(false); | ||||||||||||
627 | pOut->SetMapMode(aMap); | ||||||||||||
628 | aMtf.Record(pOut); | ||||||||||||
629 | rSdrObject.SingleObjectPainter(*pOut); | ||||||||||||
630 | aMtf.Stop(); | ||||||||||||
631 | aMtf.WindStart(); | ||||||||||||
632 | |||||||||||||
633 | // #i99268# replace the original offset from using XOutDev's SetOffset | ||||||||||||
634 | // NOT (as tried with #i92760#) with another MapMode which gets recorded | ||||||||||||
635 | // by the Metafile itself (what always leads to problems), but by | ||||||||||||
636 | // moving the result directly | ||||||||||||
637 | aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top()); | ||||||||||||
638 | aMtf.SetPrefMapMode(aMap); | ||||||||||||
639 | aMtf.SetPrefSize(aBoundRect.GetSize()); | ||||||||||||
640 | |||||||||||||
641 | if(aMtf.GetActionSize()) | ||||||||||||
642 | { | ||||||||||||
643 | aRet = aMtf; | ||||||||||||
644 | } | ||||||||||||
645 | } | ||||||||||||
646 | |||||||||||||
647 | return aRet; | ||||||||||||
648 | } | ||||||||||||
649 | |||||||||||||
650 | |||||||||||||
651 | ::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const | ||||||||||||
652 | { | ||||||||||||
653 | SortMarkedObjects(); | ||||||||||||
654 | ::std::vector< SdrObject* > aRetval; | ||||||||||||
655 | |||||||||||||
656 | ::std::vector< ::std::vector< SdrMark* > > aObjVectors( 2 ); | ||||||||||||
657 | ::std::vector< SdrMark* >& rObjVector1 = aObjVectors[ 0 ]; | ||||||||||||
658 | ::std::vector< SdrMark* >& rObjVector2 = aObjVectors[ 1 ]; | ||||||||||||
659 | const SdrLayerAdmin& rLayerAdmin = mpModel->GetLayerAdmin(); | ||||||||||||
660 | const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() ); | ||||||||||||
661 | |||||||||||||
662 | for( size_t n = 0, nCount = GetMarkedObjectCount(); n < nCount; ++n ) | ||||||||||||
663 | { | ||||||||||||
664 | SdrMark* pMark = GetSdrMarkByIndex( n ); | ||||||||||||
665 | |||||||||||||
666 | // paint objects on control layer on top of all other objects | ||||||||||||
667 | if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() ) | ||||||||||||
668 | rObjVector2.push_back( pMark ); | ||||||||||||
669 | else | ||||||||||||
670 | rObjVector1.push_back( pMark ); | ||||||||||||
671 | } | ||||||||||||
672 | |||||||||||||
673 | for(const std::vector<SdrMark*> & rObjVector : aObjVectors) | ||||||||||||
674 | { | ||||||||||||
675 | for(SdrMark* pMark : rObjVector) | ||||||||||||
676 | { | ||||||||||||
677 | aRetval.push_back(pMark->GetMarkedSdrObj()); | ||||||||||||
678 | } | ||||||||||||
679 | } | ||||||||||||
680 | |||||||||||||
681 | return aRetval; | ||||||||||||
682 | } | ||||||||||||
683 | |||||||||||||
684 | |||||||||||||
685 | void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const | ||||||||||||
686 | { | ||||||||||||
687 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); | ||||||||||||
688 | |||||||||||||
689 | if(!aSdrObjects.empty()) | ||||||||||||
690 | { | ||||||||||||
691 | sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, aSdrObjects, aSdrObjects[0]->getSdrPageFromSdrObject()); | ||||||||||||
692 | sdr::contact::DisplayInfo aDisplayInfo; | ||||||||||||
693 | |||||||||||||
694 | // do processing | ||||||||||||
695 | aPainter.ProcessDisplay(aDisplayInfo); | ||||||||||||
696 | } | ||||||||||||
697 | } | ||||||||||||
698 | |||||||||||||
699 | std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const | ||||||||||||
700 | { | ||||||||||||
701 | // Sorting the MarkList here might be problematic in the future, so | ||||||||||||
702 | // use a copy. | ||||||||||||
703 | SortMarkedObjects(); | ||||||||||||
704 | std::unique_ptr<SdrModel> pNewModel(mpModel->AllocModel()); | ||||||||||||
705 | SdrPage* pNewPage(pNewModel->AllocPage(false)); | ||||||||||||
706 | pNewModel->InsertPage(pNewPage); | ||||||||||||
707 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); | ||||||||||||
708 | |||||||||||||
709 | // #i13033# | ||||||||||||
710 | // New mechanism to re-create the connections of cloned connectors | ||||||||||||
711 | CloneList aCloneList; | ||||||||||||
712 | |||||||||||||
713 | for(SdrObject* pObj : aSdrObjects) | ||||||||||||
714 | { | ||||||||||||
715 | SdrObject* pNewObj(nullptr); | ||||||||||||
716 | |||||||||||||
717 | if(nullptr != dynamic_cast< const SdrPageObj* >(pObj)) | ||||||||||||
718 | { | ||||||||||||
719 | // convert SdrPageObj's to a graphic representation, because | ||||||||||||
720 | // virtual connection to referenced page gets lost in new model | ||||||||||||
721 | pNewObj = new SdrGrafObj( | ||||||||||||
722 | *pNewModel, | ||||||||||||
723 | GetObjGraphic(*pObj), | ||||||||||||
724 | pObj->GetLogicRect()); | ||||||||||||
725 | } | ||||||||||||
726 | else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj)) | ||||||||||||
727 | { | ||||||||||||
728 | // check if we have a valid selection *different* from whole table | ||||||||||||
729 | // being selected | ||||||||||||
730 | if(mxSelectionController.is()) | ||||||||||||
731 | { | ||||||||||||
732 | pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel); | ||||||||||||
733 | } | ||||||||||||
734 | } | ||||||||||||
735 | |||||||||||||
736 | if(nullptr == pNewObj) | ||||||||||||
737 | { | ||||||||||||
738 | // not cloned yet | ||||||||||||
739 | if(pObj->GetObjIdentifier() == OBJ_OLE2 && nullptr == mpModel->GetPersist()) | ||||||||||||
740 | { | ||||||||||||
741 | // tdf#125520 - former fix was wrong, the SdrModel | ||||||||||||
742 | // has to have a GetPersist() already, see task. | ||||||||||||
743 | // We can still warn here when this is not the case | ||||||||||||
744 | SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx" ":" "744" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx" ":" "744" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx" ), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx" ":" "744" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/svdraw/svdxcgv.cxx" ":" "744" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||||||||||
745 | } | ||||||||||||
746 | |||||||||||||
747 | // use default way | ||||||||||||
748 | pNewObj = pObj->CloneSdrObject(*pNewModel); | ||||||||||||
749 | } | ||||||||||||
750 | |||||||||||||
751 | if(pNewObj) | ||||||||||||
752 | { | ||||||||||||
753 | pNewPage->InsertObject(pNewObj, SAL_MAX_SIZE((sal_uInt64) 0xFFFFFFFFFFFFFFFFul)); | ||||||||||||
754 | |||||||||||||
755 | // #i13033# | ||||||||||||
756 | aCloneList.AddPair(pObj, pNewObj); | ||||||||||||
757 | } | ||||||||||||
758 | } | ||||||||||||
759 | |||||||||||||
760 | // #i13033# | ||||||||||||
761 | // New mechanism to re-create the connections of cloned connectors | ||||||||||||
762 | aCloneList.CopyConnections(); | ||||||||||||
763 | |||||||||||||
764 | return pNewModel; | ||||||||||||
765 | } | ||||||||||||
766 | |||||||||||||
767 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_SVX_SVDMRKV_HXX |
21 | #define INCLUDED_SVX_SVDMRKV_HXX |
22 | |
23 | #include <svx/svdmark.hxx> |
24 | #include <svx/svdhdl.hxx> |
25 | #include <svx/svdsnpv.hxx> |
26 | #include <svx/svdtypes.hxx> |
27 | #include <svx/svxdllapi.h> |
28 | #include <o3tl/typed_flags_set.hxx> |
29 | #include <basegfx/range/b2drectangle.hxx> |
30 | |
31 | |
32 | class SfxViewShell; |
33 | |
34 | // The following is not yet implemented, or just partially: |
35 | enum class SdrSearchOptions |
36 | { |
37 | NONE = 0x0000, |
38 | DEEP = 0x0001, /* recursive into group objects */ |
39 | ALSOONMASTER = 0x0002, /* MasterPages are also scanned */ |
40 | WHOLEPAGE = 0x0004, /* Not just the ObjList of PageView */ |
41 | TESTMARKABLE = 0x0008, /* just markable objects/points/handles/... */ |
42 | TESTMACRO = 0x0010, /* Just objects with macro */ |
43 | TESTTEXTEDIT = 0x0020, /* Just TextEdit-enabled objects */ |
44 | MARKED = 0x0040, /* Just marked objects/points/... */ |
45 | PASS2BOUND = 0x0080, /* In case of empty search results, then 2nd. try with BoundRectHit */ |
46 | BEFOREMARK = 0x0100, /* if one marked one found, ignore all behind that */ |
47 | |
48 | IMPISMASTER = 0x0200, /* MasterPage is being searched right now */ |
49 | PICKMARKABLE = TESTMARKABLE, |
50 | PICKTEXTEDIT = DEEP | TESTMARKABLE | TESTTEXTEDIT, |
51 | PICKMACRO = DEEP | ALSOONMASTER | WHOLEPAGE | TESTMACRO, |
52 | }; |
53 | namespace o3tl |
54 | { |
55 | template<> struct typed_flags<SdrSearchOptions> : is_typed_flags<SdrSearchOptions, 0x03ff> {}; |
56 | } |
57 | |
58 | enum class SdrHitKind |
59 | { |
60 | NONE, // No hit |
61 | Object, // Hit |
62 | Handle, // Marking handle |
63 | HelpLine, // Reference line |
64 | Gluepoint, // Glue point |
65 | TextEdit, // Open OutlinerView was hit |
66 | TextEditObj, // Object for SdrBeginTextEdit (Textbereich) |
67 | UrlField, // Field in TextObj was hit (while it is currently not edited) |
68 | Macro, // Object for BegMacroObj |
69 | MarkedObject, // Marked object (e.g. for dragging) |
70 | UnmarkedObject, // non-marked Object (e.g. for marking) |
71 | Cell // hit on a cell inside a table shape (outside of the cells text area) |
72 | }; |
73 | |
74 | enum class SdrViewEditMode { |
75 | Edit, // Also known as arrow or pointer mode |
76 | Create, // Tool for object creation |
77 | GluePointEdit // Glue point editing mode |
78 | }; |
79 | |
80 | /** options for ImpGetDescriptionString() */ |
81 | enum class ImpGetDescriptionOptions |
82 | { |
83 | NONE = 0, |
84 | POINTS = 1, |
85 | GLUEPOINTS = 2, |
86 | }; |
87 | |
88 | class ImplMarkingOverlay; |
89 | class MarkingSubSelectionOverlay; |
90 | |
91 | class SVXCORE_DLLPUBLIC__attribute__ ((visibility("default"))) SdrMarkView : public SdrSnapView |
92 | { |
93 | friend class SdrPageView; |
94 | |
95 | // #114409#-3 Migrate selections |
96 | std::unique_ptr<ImplMarkingOverlay> mpMarkObjOverlay; |
97 | std::unique_ptr<ImplMarkingOverlay> mpMarkPointsOverlay; |
98 | std::unique_ptr<ImplMarkingOverlay> mpMarkGluePointsOverlay; |
99 | |
100 | std::unique_ptr<MarkingSubSelectionOverlay> mpMarkingSubSelectionOverlay; |
101 | |
102 | protected: |
103 | SdrObject* mpMarkedObj; // If not just one object ( i.e. More than one object ) is marked. |
104 | SdrPageView* mpMarkedPV; // If all marked objects are situated on the same PageView. |
105 | |
106 | Point maRef1; // Persistent - Rotation center / axis of reflection |
107 | Point maRef2; // Persistent |
108 | SdrHdlList maHdlList; |
109 | |
110 | sdr::ViewSelection maSdrViewSelection; |
111 | |
112 | std::vector<basegfx::B2DRectangle> maSubSelectionList; |
113 | tools::Rectangle maMarkedObjRect; |
114 | tools::Rectangle maMarkedPointsRect; |
115 | tools::Rectangle maMarkedGluePointsRect; |
116 | |
117 | static constexpr sal_uInt16 mnFrameHandlesLimit = 50; |
118 | |
119 | SdrDragMode meDragMode; // Persistent |
120 | SdrViewEditMode meEditMode; // Persistent |
121 | SdrViewEditMode meEditMode0; // Persistent |
122 | |
123 | bool mbDesignMode : 1; // DesignMode for SdrUnoObj |
124 | bool mbForceFrameHandles : 1; // Persistent - FrameDrag also for single objects |
125 | bool mbPlusHdlAlways : 1; // Persistent |
126 | bool mbInsPolyPoint : 1; // at this time InsPolyPointDragging |
127 | bool mbMarkedObjRectDirty : 1; |
128 | bool mbMrkPntDirty : 1; |
129 | bool mbMarkedPointsRectsDirty : 1; |
130 | |
131 | // flag to completely disable handles at the view |
132 | bool mbMarkHandlesHidden : 1; |
133 | |
134 | // Helper to get a possible GridOffset from SdrObject |
135 | bool getPossibleGridOffsetForSdrObject( |
136 | basegfx::B2DVector& rOffset, |
137 | const SdrObject* pObj, |
138 | const SdrPageView* pPV) const; |
139 | |
140 | // Helper to get a possible GridOffset from Position |
141 | bool getPossibleGridOffsetForPosition( |
142 | basegfx::B2DVector& rOffset, |
143 | const basegfx::B2DPoint& rPoint, |
144 | const SdrPageView* pPV) const; |
145 | |
146 | private: |
147 | SVX_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImpSetPointsRects() const; |
148 | void UndirtyMrkPnt() const; |
149 | |
150 | void SetMarkHandlesForLOKit(tools::Rectangle const & rRect, const SfxViewShell* pOtherShell); |
151 | |
152 | protected: |
153 | virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override; |
154 | virtual void ModelHasChanged() override; // Is called by the PaintView |
155 | virtual void SetMarkHandles(SfxViewShell* pOtherShell); // maHdlList - fill (List of handles) |
156 | void SetMarkRects(); // Rects at the PageViews |
157 | void CheckMarked(); // Scan MarkList after Del and Lock Layer ... |
158 | void AddDragModeHdl(SdrDragMode eMode); |
159 | virtual bool MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin) override; |
160 | virtual bool RequestHelp(const HelpEvent& rHEvt) override; |
161 | |
162 | // add custom handles (used by other apps, e.g. AnchorPos) |
163 | virtual void AddCustomHdl(); |
164 | |
165 | void ForceRefToMarked(); |
166 | void ForceUndirtyMrkPnt() const { if (mbMrkPntDirty) UndirtyMrkPnt(); } |
167 | |
168 | virtual SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const; |
169 | SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj) const; |
170 | SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj,const SdrMarkList * pMarkList) const; |
171 | bool ImpIsFrameHandles() const; |
172 | OUString ImpGetDescriptionString(const char* pStrCacheID, ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE) const; |
173 | |
174 | // Generates a string including degrees symbol, from an angel specification in 1/100deg |
175 | bool ImpMarkPoint(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark); |
176 | virtual bool MarkPoints(const tools::Rectangle* pRect, bool bUnmark); |
177 | bool MarkGluePoints(const tools::Rectangle* pRect, bool bUnmark); |
178 | |
179 | void SetMoveOutside(bool bOn); |
180 | bool MarkableObjectsExceed( int n ) const; |
181 | |
182 | protected: |
183 | // #i71538# make constructors of SdrView sub-components protected to avoid incomplete incarnations which may get casted to SdrView |
184 | SdrMarkView( |
185 | SdrModel& rSdrModel, |
186 | OutputDevice* pOut); |
187 | |
188 | virtual ~SdrMarkView() override; |
189 | |
190 | public: |
191 | virtual bool IsAction() const override; |
192 | virtual void MovAction(const Point& rPnt) override; |
193 | virtual void EndAction() override; |
194 | virtual void BckAction() override; |
195 | virtual void BrkAction() override; |
196 | virtual void TakeActionRect(tools::Rectangle& rRect) const override; |
197 | |
198 | virtual void ClearPageView() override; |
199 | virtual void HideSdrPage() override; |
200 | bool IsObjMarkable(SdrObject const * pObj, SdrPageView const * pPV) const; |
201 | |
202 | // Returns sal_True if objects, points or glue points are selected by drawing a frame |
203 | // (as long as the frame is drawn). |
204 | bool IsMarking() const { return IsMarkObj() || IsMarkPoints() || IsMarkGluePoints(); } |
205 | |
206 | // Marking objects by drawing of a selection frame |
207 | void BegMarkObj(const Point& rPnt, bool bUnmark = false); |
208 | void MovMarkObj(const Point& rPnt); |
209 | bool EndMarkObj(); |
210 | void BrkMarkObj(); |
211 | bool IsMarkObj() const { return (nullptr != mpMarkObjOverlay); } |
212 | |
213 | // DragModes: SDRDRAG_CREATE,SdrDragMode::Move,SdrDragMode::Resize,SdrDragMode::Rotate,SdrDragMode::Mirror,SdrDragMode::Shear,SdrDragMode::Crook |
214 | // Move==Resize |
215 | // The interface might maybe be changed in the future because of Ortho-Drag |
216 | void SetDragMode(SdrDragMode eMode); |
217 | SdrDragMode GetDragMode() const { return meDragMode; } |
218 | void SetFrameHandles(bool bOn); |
219 | bool IsFrameHandles() const { return mbForceFrameHandles; } |
220 | |
221 | // returns true if number of markable objects is greater than 1 |
222 | bool HasMultipleMarkableObjects() const { return MarkableObjectsExceed(1); }; |
223 | |
224 | void SetEditMode(SdrViewEditMode eMode); |
225 | SdrViewEditMode GetEditMode() const { return meEditMode; } |
226 | |
227 | void SetEditMode(bool bOn) { SetEditMode(bOn?SdrViewEditMode::Edit:SdrViewEditMode::Create); } |
228 | bool IsEditMode() const { return meEditMode==SdrViewEditMode::Edit; } |
229 | void SetCreateMode(bool bOn) { SetEditMode(bOn?SdrViewEditMode::Create:SdrViewEditMode::Edit); } |
230 | bool IsCreateMode() const { return meEditMode==SdrViewEditMode::Create; } |
231 | void SetGluePointEditMode(bool bOn) { SetEditMode(bOn?SdrViewEditMode::GluePointEdit:meEditMode0); } |
232 | bool IsGluePointEditMode() const { return meEditMode==SdrViewEditMode::GluePointEdit; } |
233 | |
234 | void SetDesignMode(bool bOn = true); |
235 | bool IsDesignMode() const { return mbDesignMode; } |
236 | |
237 | void SetFrameDragSingles(bool bOn=true) { SetFrameHandles(bOn); } |
238 | bool IsFrameDragSingles() const { return IsFrameHandles(); } |
239 | |
240 | bool HasMarkableObj() const { return MarkableObjectsExceed(0); }; |
241 | |
242 | |
243 | // migrate selections |
244 | |
245 | protected: |
246 | // all available changing methods |
247 | SdrMarkList& GetMarkedObjectListWriteAccess() { return maSdrViewSelection.GetMarkedObjectListWriteAccess(); } |
248 | |
249 | public: |
250 | // all available const methods for read access to selection |
251 | const SdrMarkList& GetMarkedObjectList() const { return maSdrViewSelection.GetMarkedObjectList(); } |
252 | // returns SAL_MAX_SIZE if not found |
253 | size_t TryToFindMarkedObject(const SdrObject* pObj) const { return GetMarkedObjectList().FindObject(pObj); } |
254 | SdrPageView* GetSdrPageViewOfMarkedByIndex(size_t nNum) const { return GetMarkedObjectList().GetMark(nNum)->GetPageView(); } |
255 | SdrMark* GetSdrMarkByIndex(size_t nNum) const { return GetMarkedObjectList().GetMark(nNum); } |
256 | SdrObject* GetMarkedObjectByIndex(size_t nNum) const { return GetMarkedObjectList().GetMark(nNum)->GetMarkedSdrObj(); } |
257 | size_t GetMarkedObjectCount() const { return GetMarkedObjectList().GetMarkCount(); } |
258 | void SortMarkedObjects() const { GetMarkedObjectList().ForceSort(); } |
259 | bool AreObjectsMarked() const { return 0 != GetMarkedObjectList().GetMarkCount(); } |
260 | OUString const & GetDescriptionOfMarkedObjects() const { return GetMarkedObjectList().GetMarkDescription(); } |
261 | OUString const & GetDescriptionOfMarkedPoints() const { return GetMarkedObjectList().GetPointMarkDescription(); } |
262 | OUString const & GetDescriptionOfMarkedGluePoints() const { return GetMarkedObjectList().GetGluePointMarkDescription(); } |
263 | |
264 | // Get a list of all those links which are connected to marked nodes, |
265 | // but which are not marked themselves. |
266 | const SdrMarkList& GetEdgesOfMarkedNodes() const { return maSdrViewSelection.GetEdgesOfMarkedNodes(); } |
267 | const SdrMarkList& GetMarkedEdgesOfMarkedNodes() const { return maSdrViewSelection.GetMarkedEdgesOfMarkedNodes(); } |
268 | const std::vector<SdrObject*>& GetTransitiveHullOfMarkedObjects() const { return maSdrViewSelection.GetAllMarkedObjects(); } |
269 | |
270 | |
271 | // mechanism to complete disable handles at the view. Handles will be hidden and deleted |
272 | // when set, no new ones created, no interaction allowed. Handles will be recreated and shown |
273 | // when reset. Default is false. |
274 | void hideMarkHandles(); |
275 | void showMarkHandles(); |
276 | bool areMarkHandlesHidden() const { return mbMarkHandlesHidden; } |
277 | |
278 | bool IsMarkedHit(const Point& rPnt, short nTol=-2) const { return IsMarkedObjHit(rPnt,nTol); } |
279 | bool IsMarkedObjHit(const Point& rPnt, short nTol=-2) const; |
280 | |
281 | SdrHdl* PickHandle(const Point& rPnt) const; |
282 | |
283 | // Pick: Supported options for nOptions are: |
284 | // SdrSearchOptions::DEEP SdrSearchOptions::ALSOONMASTER SdrSearchOptions::TESTMARKABLE SdrSearchOptions::TESTTEXTEDIT |
285 | // SdrSearchOptions::MARKED |
286 | // SdrSearchOptions::WHOLEPAGE |
287 | SdrObject* PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions, SdrObject** ppRootObj, bool* pbHitPassDirect=nullptr) const; |
288 | SdrObject* PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions=SdrSearchOptions::NONE) const; |
289 | bool MarkObj(const Point& rPnt, short nTol=-2, bool bToggle=false, bool bDeep=false); |
290 | |
291 | // Pick: Supported options for nOptions are SdrSearchOptions::PASS2BOUND |
292 | bool PickMarkedObj(const Point& rPnt, SdrObject*& rpObj, SdrPageView*& rpPV, SdrSearchOptions nOptions) const; |
293 | |
294 | // Selects the most upper of the marked objects (O1) and scans from there |
295 | // towards bottom direction, selecting the first non-marked object (O2). |
296 | // In case of success the marking of O1 is deleted, a marking is created at |
297 | // O2 and TRUE is returned. With the parameter bPrev=sal_True the scan |
298 | // direction is turned to the other direction. |
299 | bool MarkNextObj(bool bPrev=false); |
300 | |
301 | // Selects the most upper of the marked objects which is hit by rPnt/nTol |
302 | // and scans from there to bottom direction, selecting the first non-marked |
303 | // object (O2). In case of success the marking of O1 is deleted, a marking |
304 | // is created at O2 and sal_True is returned. With the parameter |
305 | // bPrev=sal_True the scan direction is turned to the other direction. |
306 | bool MarkNextObj(const Point& rPnt, short nTol, bool bPrev); |
307 | |
308 | // Mark all objects within a rectangular area |
309 | // Just objects are marked which are inclosed completely |
310 | void MarkObj(const tools::Rectangle& rRect, bool bUnmark); |
311 | void MarkObj(SdrObject* pObj, SdrPageView* pPV, bool bUnmark = false, bool bDoNoSetMarkHdl = false, |
312 | std::vector<basegfx::B2DRectangle> const & rSubSelections = std::vector<basegfx::B2DRectangle>()); |
313 | void MarkAllObj(SdrPageView* pPV=nullptr); // pPage=NULL => all displayed pages |
314 | void UnmarkAllObj(SdrPageView const * pPV=nullptr); // pPage=NULL => all displayed pages |
315 | |
316 | // This function is time-consuming intensive, as the MarkList has to be scanned. |
317 | bool IsObjMarked(SdrObject const * pObj) const; |
318 | void UnMarkAll(SdrPageView const * pPV=nullptr) { UnmarkAllObj(pPV); } |
319 | |
320 | // Request/set the size of the marking handles. Declaration in Pixel. |
321 | // The value is meant to be the edge length ( link length ). |
322 | // Pair values are round up to impair values: 3->3, 4->5, 5->5, 6->7, 7->7, ... |
323 | // Default value is 7, minimum value is 3 Pixels. |
324 | sal_uInt16 GetMarkHdlSizePixel() const; |
325 | void SetMarkHdlSizePixel(sal_uInt16 nSiz); |
326 | |
327 | virtual bool HasMarkablePoints() const; |
328 | virtual sal_Int32 GetMarkablePointCount() const; |
329 | virtual bool HasMarkedPoints() const; |
330 | |
331 | // There might be points which can't be marked: |
332 | bool IsPointMarkable(const SdrHdl& rHdl) const; |
333 | virtual bool MarkPoint(SdrHdl& rHdl, bool bUnmark=false); |
334 | |
335 | /** should only be used from outside svx for special ui elements */ |
336 | bool MarkPointHelper(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark); |
337 | |
338 | bool UnmarkPoint(SdrHdl& rHdl) { return MarkPoint(rHdl,true); } |
339 | bool IsPointMarked(const SdrHdl& rHdl) const { ForceUndirtyMrkPnt(); return rHdl.IsSelected(); } |
340 | bool MarkAllPoints() { return MarkPoints(nullptr,false); } |
341 | bool UnmarkAllPoints() { return MarkPoints(nullptr,true); } |
342 | |
343 | // Selects the first marked point (P1) which is hit by rPnt |
344 | // and from there it searches the first non-marked point(P2). |
345 | // In case of success the marking of |
346 | // P1 is deleted, a mark is set at P2. |
347 | void MarkNextPoint(); |
348 | |
349 | // Search for the number of the suitable handle. In case of empty search result, |
350 | // SAL_MAX_SIZE is returned. |
351 | size_t GetHdlNum(SdrHdl const * pHdl) const { return maHdlList.GetHdlNum(pHdl); } |
352 | SdrHdl* GetHdl(size_t nHdlNum) const { return maHdlList.GetHdl(nHdlNum); } |
353 | const SdrHdlList& GetHdlList() const { return maHdlList; } |
354 | |
355 | // Draw a selection frame for marking of points. |
356 | // This routine will just be started in case that HasMarkablePoints() returns sal_True. |
357 | bool BegMarkPoints(const Point& rPnt, bool bUnmark = false); |
358 | void MovMarkPoints(const Point& rPnt); |
359 | bool EndMarkPoints(); |
360 | void BrkMarkPoints(); |
361 | bool IsMarkPoints() const { return (nullptr != mpMarkPointsOverlay); } |
362 | |
363 | // Select that additional handles are displayed permanently. |
364 | void SetPlusHandlesAlwaysVisible(bool bOn); |
365 | bool IsPlusHandlesAlwaysVisible() const { return mbPlusHdlAlways; } |
366 | |
367 | bool HasMarkableGluePoints() const; |
368 | bool HasMarkedGluePoints() const; |
369 | |
370 | // A gluepoint is clearly identified by the SdrObject |
371 | // (to which it belongs) as well as by a sal_uInt16 nId (as each SdrObject may consist of |
372 | // several glue points. Here at the View there is an additional |
373 | // SdrPageView, which should be defined correctly always. |
374 | // Alternatively a gluepoint may be characterized by a SdrHdl. |
375 | // In this case the SdrHdl instance consists of all required information. |
376 | // And in this case, the glue point are always is marked by enforcement |
377 | // (Handlers are just situated at marked gluepoints ) |
378 | // Attention: With each change of the glue point status the handle list is re-calculated. |
379 | // All previously saved SdrHdl* became invalid by this, the same with the point IDs! |
380 | bool PickGluePoint(const Point& rPnt, SdrObject*& rpObj, sal_uInt16& rnId, SdrPageView*& rpPV) const; |
381 | bool MarkGluePoint(const SdrObject* pObj, sal_uInt16 nId, bool bUnmark); |
382 | void UnmarkGluePoint(const SdrObject* pObj, sal_uInt16 nId) { MarkGluePoint(pObj,nId,true); } |
383 | bool IsGluePointMarked(const SdrObject* pObj, sal_uInt16 nId) const; |
384 | |
385 | // Get the Hdl (handle) of a marked GluePoint. Non-marked |
386 | // GluePoints don`t have handles |
387 | SdrHdl* GetGluePointHdl(const SdrObject* pObj, sal_uInt16 nId) const; |
388 | |
389 | // Mark all points within this rectangular (View coordinates) |
390 | bool MarkAllGluePoints() { return MarkGluePoints(nullptr,false); } |
391 | bool UnmarkAllGluePoints() { return MarkGluePoints(nullptr,true); } |
392 | |
393 | // Selects the first marked point (P1) which is hit by rPnt |
394 | // and from there it searches the first non-marked point(P2). |
395 | // In case of success the marking of |
396 | // P1 is deleted, a mark is set at P2. |
397 | void MarkNextGluePoint(); |
398 | |
399 | // Draw a selection frame for glue point marking. |
400 | // This routine will just be started in case that HasMarkablePoints() returns sal_True. |
401 | // The GlueEditMode sal_True is disregarded. |
402 | // bool BegMarkGluePoints(const Point& rPnt, OutputDevice* pOut); |
403 | bool BegMarkGluePoints(const Point& rPnt, bool bUnmark = false); |
404 | void MovMarkGluePoints(const Point& rPnt); |
405 | void EndMarkGluePoints(); |
406 | void BrkMarkGluePoints(); |
407 | bool IsMarkGluePoints() const { return (nullptr != mpMarkGluePointsOverlay); } |
408 | |
409 | // bRestraintPaint=sal_False causes the handles not to be drawn immediately. |
410 | // AdjustMarkHdl is just called in case of changes; usually this causes an Invalidate |
411 | // At the end of a redraw the handles are drawn automatically. |
412 | // The purpose is to avoid unnecessary flickering. -> This does not yet work, that's why sal_True! |
413 | void AdjustMarkHdl(SfxViewShell* pOtherShell = nullptr); //HMHBOOL bRestraintPaint=sal_True); |
414 | |
415 | const tools::Rectangle& GetMarkedObjRect() const; // SnapRects of Objects, without line width |
416 | tools::Rectangle GetMarkedObjBoundRect() const; // incl. line width, overlapping rags, ... |
417 | const tools::Rectangle& GetMarkedPointsRect() const; // Enclosing rectangle of all marked points |
418 | const tools::Rectangle& GetMarkedGluePointsRect() const; // Enclosing rectangle of all marked glue points |
419 | const tools::Rectangle& GetAllMarkedRect() const { return GetMarkedObjRect(); } |
420 | tools::Rectangle GetAllMarkedBoundRect() const { return GetMarkedObjBoundRect(); } |
421 | |
422 | // Will be always called, if the list of marked objects might be changed. |
423 | // If you override this method, be sure that you call the |
424 | // methods of the base class! |
425 | virtual void MarkListHasChanged(); |
426 | |
427 | // Entering (Editing) of a maybe marked object group. If there are several |
428 | // object groups marked, the most upper group is selected. After that |
429 | // all member objects of the group are directly accessible. All other |
430 | // objects may not be processed in the meantime (until the next |
431 | // LeaveGroup()). With markings which overlaps pages, every page is processed |
432 | // separately. The method returns sal_True, if at least one group was entered. |
433 | void EnterMarkedGroup(); |
434 | |
435 | // Rotation center point and start point of the axis of reflection, respectively |
436 | const Point& GetRef1() const { return maRef1; } |
437 | void SetRef1(const Point& rPt); |
438 | |
439 | // End point of the axis of reflection |
440 | const Point& GetRef2() const { return maRef2; } |
441 | void SetRef2(const Point& rPt); |
442 | /// Get access to the view shell owning this draw view, if any. |
443 | virtual SfxViewShell* GetSfxViewShell() const; |
444 | }; |
445 | |
446 | |
447 | // - Hit tolerances: |
448 | // It has to be declared in logical coordinates. So please translate the |
449 | // wanted pixel value with PixelToLogic in Logical values. |
450 | // Taking as example a logical value of 100: |
451 | // - For a horizontal hairline (Object with height 0), the generated data is +/-100, i.e. |
452 | // a vertical area of 200 logical units is sensitive. |
453 | // - For a polygon, a rectangular of the size (200,200) is generated and a |
454 | // touch test between Poly and this Rect is processed. |
455 | // - Objects which respond SdrObject::HasEdit()==TRUE ( e.g. a text frame ), |
456 | // are specially treated: An additional sensitive area with a width of |
457 | // 2*Tol (200 units for this example) is created around the object. |
458 | // When an object is directly hit, the Edit method is called. |
459 | // In opposite, a hit in the surrounding sensitive area enables Dragging. |
460 | |
461 | |
462 | #endif // INCLUDED_SVX_SVDMRKV_HXX |
463 | |
464 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_VCL_BITMAPEX_HXX |
21 | #define INCLUDED_VCL_BITMAPEX_HXX |
22 | |
23 | #include <vcl/dllapi.h> |
24 | #include <vcl/alpha.hxx> |
25 | #include <vcl/Scanline.hxx> |
26 | #include <tools/color.hxx> |
27 | |
28 | #include <sal/types.h> |
29 | |
30 | namespace com::sun::star::rendering { |
31 | class XBitmapCanvas; |
32 | } |
33 | namespace com::sun::star::uno { template <class interface_type> class Reference; } |
34 | namespace basegfx { class BColorModifierStack; } |
35 | |
36 | enum class TransparentType |
37 | { |
38 | NONE, |
39 | Color, |
40 | Bitmap |
41 | }; |
42 | |
43 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VCL_DLLPUBLIC__attribute__ ((visibility("default"))) BitmapEx |
44 | { |
45 | public: |
46 | |
47 | BitmapEx(); |
48 | explicit BitmapEx( const OUString& rIconName ); |
49 | BitmapEx( const BitmapEx& rBitmapEx ); |
50 | BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ); |
51 | BitmapEx( Size aSize, sal_uInt16 nBitCount ); |
52 | explicit BitmapEx( const Bitmap& rBmp ); |
53 | BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ); |
54 | BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ); |
55 | BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ); |
56 | |
57 | BitmapEx& operator=( const BitmapEx& rBitmapEx ); |
58 | BitmapEx& operator=( const Bitmap& rBitmap ) { return operator=(BitmapEx(rBitmap)); } |
59 | bool operator==( const BitmapEx& rBitmapEx ) const; |
60 | bool operator!=( const BitmapEx& rBitmapEx ) const { return !(*this==rBitmapEx); } |
61 | bool operator!() const { return !maBitmap; } |
62 | |
63 | bool IsEmpty() const; |
64 | void SetEmpty(); |
65 | void Clear(); |
66 | |
67 | void Draw( OutputDevice* pOutDev, |
68 | const Point& rDestPt ) const; |
69 | void Draw( OutputDevice* pOutDev, |
70 | const Point& rDestPt, const Size& rDestSize ) const; |
71 | |
72 | bool IsTransparent() const; |
73 | TransparentType GetTransparentType() const { return meTransparent; } |
74 | |
75 | Bitmap GetBitmap( Color aTransparentReplaceColor ) const; |
76 | /// Gives direct access to the contained bitmap. |
77 | const Bitmap& GetBitmap() const; |
78 | Bitmap GetMask() const; |
79 | |
80 | bool IsAlpha() const; |
81 | AlphaMask GetAlpha() const; |
82 | |
83 | const Size& GetSizePixel() const { return maBitmapSize; } |
84 | void SetSizePixel(const Size& rNewSize); |
85 | |
86 | const Size& GetPrefSize() const { return maBitmap.GetPrefSize(); } |
87 | void SetPrefSize( const Size& rPrefSize ) { maBitmap.SetPrefSize( rPrefSize ); } |
88 | |
89 | const MapMode& GetPrefMapMode() const { return maBitmap.GetPrefMapMode(); } |
90 | void SetPrefMapMode( const MapMode& rPrefMapMode ) { maBitmap.SetPrefMapMode( rPrefMapMode ); } |
91 | |
92 | const Color& GetTransparentColor() const { return maTransparentColor; } |
93 | |
94 | sal_uInt16 GetBitCount() const { return maBitmap.GetBitCount(); } |
95 | sal_uLong GetSizeBytes() const; |
96 | BitmapChecksum GetChecksum() const; |
97 | |
98 | /** Convert bitmap format |
99 | |
100 | @param eConversion |
101 | The format this bitmap should be converted to. |
102 | |
103 | @return true, if the conversion was completed successfully. |
104 | */ |
105 | bool Convert( BmpConversion eConversion ); |
106 | |
107 | /** Crop the bitmap |
108 | |
109 | @param rRectPixel |
110 | A rectangle specifying the crop amounts on all four sides of |
111 | the bitmap. If the upper left corner of the bitmap is assigned |
112 | (0,0), then this method cuts out the given rectangle from the |
113 | bitmap. Note that the rectangle is clipped to the bitmap's |
114 | dimension, i.e. negative left,top rectangle coordinates or |
115 | exceeding width or height is ignored. |
116 | |
117 | @return true, if cropping was performed successfully. If |
118 | nothing had to be cropped, because e.g. the crop rectangle |
119 | included the bitmap, false is returned, too! |
120 | */ |
121 | bool Crop( const tools::Rectangle& rRectPixel ); |
122 | |
123 | /** Expand the bitmap by pixel padding |
124 | |
125 | @param nDX |
126 | Number of pixel to pad at the right border of the bitmap |
127 | |
128 | @param nDY |
129 | Number of scanlines to pad at the bottom border of the bitmap |
130 | |
131 | @param bExpandTransparent |
132 | Whether to expand the transparency color or not. |
133 | */ |
134 | void Expand( |
135 | sal_uLong nDX, sal_uLong nDY, |
136 | bool bExpandTransparent = false ); |
137 | |
138 | /** Copy a rectangular area from another bitmap |
139 | |
140 | @param rRectDst |
141 | Destination rectangle in this bitmap. This is clipped to the |
142 | bitmap dimensions. |
143 | |
144 | @param rRectSrc |
145 | Source rectangle in pBmpSrc. This is clipped to the source |
146 | bitmap dimensions. Note further that no scaling takes place |
147 | during this copy operation, i.e. only the minimum of source |
148 | and destination rectangle's width and height are used. |
149 | |
150 | @param pBmpExSrc |
151 | The source bitmap to copy from. If this argument is NULL, or |
152 | equal to the object this method is called on, copying takes |
153 | place within the same bitmap. |
154 | |
155 | @return true, if the operation completed successfully. false |
156 | is not only returned when the operation failed, but also if |
157 | nothing had to be done, e.g. because one of the rectangles are |
158 | empty. |
159 | */ |
160 | bool CopyPixel( |
161 | const tools::Rectangle& rRectDst, |
162 | const tools::Rectangle& rRectSrc, |
163 | const BitmapEx* pBmpExSrc ); |
164 | |
165 | /** Fill the entire bitmap with the given color |
166 | |
167 | @param rFillColor |
168 | Color value to use for filling. Set the transparency part of |
169 | the color to fill the mask. |
170 | |
171 | @return true, if the operation was completed successfully. |
172 | */ |
173 | bool Erase( const Color& rFillColor ); |
174 | |
175 | /** Perform the Invert operation on every pixel |
176 | |
177 | @return true, if the operation was completed successfully. |
178 | */ |
179 | bool Invert(); |
180 | |
181 | /** Mirror the bitmap |
182 | |
183 | @param nMirrorFlags |
184 | About which axis (horizontal, vertical, or both) to mirror |
185 | |
186 | @return true, if the operation was completed successfully. |
187 | */ |
188 | bool Mirror( BmpMirrorFlags nMirrorFlags ); |
189 | |
190 | /** Scale the bitmap |
191 | |
192 | @param rNewSize |
193 | The resulting size of the scaled bitmap |
194 | |
195 | @param nScaleFlag |
196 | The algorithm to be used for scaling |
197 | |
198 | @return true, if the operation was completed successfully. |
199 | */ |
200 | bool Scale( |
201 | const Size& rNewSize, |
202 | BmpScaleFlag nScaleFlag = BmpScaleFlag::Default ); |
203 | |
204 | /** Scale the bitmap |
205 | |
206 | @param rScaleX |
207 | The scale factor in x direction. |
208 | |
209 | @param rScaleY |
210 | The scale factor in y direction. |
211 | |
212 | @param nScaleFlag |
213 | The algorithm to be used for scaling |
214 | |
215 | @return true, if the operation was completed successfully. |
216 | */ |
217 | bool Scale( |
218 | const double& rScaleX, |
219 | const double& rScaleY, |
220 | BmpScaleFlag nScaleFlag = BmpScaleFlag::Default ); |
221 | |
222 | /** Rotate bitmap by the specified angle |
223 | |
224 | @param nAngle10 |
225 | The rotation angle in tenth of a degree. The bitmap is always rotated around its center. |
226 | |
227 | @param rFillColor |
228 | The color to use for filling blank areas. During rotation, the |
229 | bitmap is enlarged such that the whole rotation result fits |
230 | in. The empty spaces around that rotated original bitmap are |
231 | then filled with this color. |
232 | |
233 | @return true, if the operation was completed successfully. |
234 | */ |
235 | bool Rotate( |
236 | long nAngle10, |
237 | const Color& rFillColor ); |
238 | |
239 | /** Replace all pixel having the search color with the specified color |
240 | |
241 | @param rSearchColor |
242 | Color specifying which pixel should be replaced |
243 | |
244 | @param rReplaceColor |
245 | Color to be placed in all changed pixel |
246 | */ |
247 | void Replace( |
248 | const Color& rSearchColor, |
249 | const Color& rReplaceColor ); |
250 | |
251 | /** Replace all pixel having the search color with the specified color |
252 | |
253 | @param rSearchColor |
254 | Color specifying which pixel should be replaced |
255 | |
256 | @param rReplaceColor |
257 | Color to be placed in all changed pixel |
258 | |
259 | @param nTolerance |
260 | Tolerance value. Specifies the maximal difference between |
261 | rSearchColor and the individual pixel values, such that the |
262 | corresponding pixel is still regarded a match. |
263 | */ |
264 | void Replace( |
265 | const Color& rSearchColor, |
266 | const Color& rReplaceColor, |
267 | sal_uInt8 nTolerance ); |
268 | |
269 | /** Replace all pixel having one the search colors with the corresponding replace color |
270 | |
271 | @param pSearchColors |
272 | Array of colors specifying which pixel should be replaced |
273 | |
274 | @param pReplaceColors |
275 | Array of colors to be placed in all changed pixel |
276 | |
277 | @param nColorCount |
278 | Size of the aforementioned color arrays |
279 | |
280 | @param pTols |
281 | Tolerance value. Specifies the maximal difference between |
282 | pSearchColor colors and the individual pixel values, such that |
283 | the corresponding pixel is still regarded a match. |
284 | */ |
285 | void Replace( |
286 | const Color* pSearchColors, |
287 | const Color* pReplaceColors, |
288 | sal_uLong nColorCount ); |
289 | |
290 | /** Replace all pixel having one the search colors with the corresponding replace color |
291 | |
292 | @param pSearchColors |
293 | Array of colors specifying which pixel should be replaced |
294 | |
295 | @param rReplaceColors |
296 | Array of colors to be placed in all changed pixel |
297 | |
298 | @param nColorCount |
299 | Size of the aforementioned color arrays |
300 | |
301 | @param pTols |
302 | Tolerance value. Specifies the maximal difference between |
303 | pSearchColor colors and the individual pixel values, such that |
304 | the corresponding pixel is still regarded a match. |
305 | |
306 | @return true, if the operation was completed successfully. |
307 | */ |
308 | void Replace( |
309 | const Color* pSearchColors, |
310 | const Color* pReplaceColors, |
311 | sal_uLong nColorCount, |
312 | sal_uInt8 const * pTols ); |
313 | |
314 | /** Replace transparency with given color. |
315 | */ |
316 | void ReplaceTransparency( const Color& rColor ); |
317 | |
318 | /** Get contours in image */ |
319 | tools::Polygon GetContour( bool bContourEdgeDetect, const tools::Rectangle* pWorkRect ); |
320 | |
321 | /** Change various global color characteristics |
322 | |
323 | @param nLuminancePercent |
324 | Percent of luminance change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
325 | |
326 | @param nContrastPercent |
327 | Percent of contrast change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
328 | |
329 | @param nChannelRPercent |
330 | Percent of red channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
331 | |
332 | @param nChannelGPercent |
333 | Percent of green channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
334 | |
335 | @param nChannelBPercent |
336 | Percent of blue channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
337 | |
338 | @param fGamma |
339 | Exponent of the gamma function applied to the bitmap. The |
340 | value 1.0 results in no change, the valid range is |
341 | (0.0,10.0]. Values outside this range are regarded as 1.0. |
342 | |
343 | @param bInvert |
344 | If true, invert the channel values with the logical 'not' operator |
345 | |
346 | @param msoBrightness |
347 | Use the same formula for brightness as used by MSOffice. |
348 | |
349 | @return true, if the operation was completed successfully. |
350 | */ |
351 | bool Adjust( |
352 | short nLuminancePercent, |
353 | short nContrastPercent, |
354 | short nChannelRPercent, |
355 | short nChannelGPercent, |
356 | short nChannelBPercent, |
357 | double fGamma = 1.0, |
358 | bool bInvert = false, |
359 | bool msoBrightness = false ); |
360 | |
361 | /** Get transparency at given position |
362 | |
363 | @param nX |
364 | integer X-Position in Bitmap |
365 | |
366 | @param nY |
367 | integer Y-Position in Bitmap |
368 | |
369 | @return transparency value in the range of [0 .. 255] where |
370 | 0 is not transparent, 255 is fully transparent |
371 | */ |
372 | sal_uInt8 GetTransparency( |
373 | sal_Int32 nX, |
374 | sal_Int32 nY) const; |
375 | |
376 | /** Get pixel color (including alpha) at given position |
377 | |
378 | @param nX |
379 | integer X-Position in Bitmap |
380 | |
381 | @param nY |
382 | integer Y-Position in Bitmap |
383 | */ |
384 | ::Color GetPixelColor( |
385 | sal_Int32 nX, |
386 | sal_Int32 nY) const; |
387 | |
388 | /** Create transformed Bitmap |
389 | |
390 | @param fWidth |
391 | The target width in pixels |
392 | |
393 | @param fHeight |
394 | The target height in pixels |
395 | |
396 | @param rTransformation |
397 | The back transformation for each pixel in (0 .. fWidth),(0 .. fHeight) to |
398 | local pixel coordinates |
399 | */ |
400 | [[nodiscard]] |
401 | BitmapEx TransformBitmapEx( |
402 | double fWidth, |
403 | double fHeight, |
404 | const basegfx::B2DHomMatrix& rTransformation) const; |
405 | |
406 | /** Create transformed Bitmap |
407 | |
408 | @param rTransformation |
409 | The transformation from unit coordinates to the unit range |
410 | |
411 | @param rVisibleRange |
412 | The relative visible range in unit coordinates, relative to (0,0,1,1) which |
413 | defines the whole target area |
414 | |
415 | @param fMaximumArea |
416 | A limitation for the maximum size of pixels to use for the result |
417 | |
418 | The target size of the result bitmap is defined by transforming the given |
419 | rTargetRange with the given rTransformation; the area of the result is |
420 | linearly scaled to not exceed the given fMaximumArea |
421 | |
422 | @return The transformed bitmap |
423 | */ |
424 | [[nodiscard]] |
425 | BitmapEx getTransformed( |
426 | const basegfx::B2DHomMatrix& rTransformation, |
427 | const basegfx::B2DRange& rVisibleRange, |
428 | double fMaximumArea) const; |
429 | |
430 | /** Create ColorStack-modified version of this BitmapEx |
431 | |
432 | @param rBColorModifierStack |
433 | A ColrModifierStack which defines how each pixel has to be modified |
434 | */ |
435 | [[nodiscard]] |
436 | BitmapEx ModifyBitmapEx( const basegfx::BColorModifierStack& rBColorModifierStack) const; |
437 | |
438 | [[nodiscard]] |
439 | static BitmapEx AutoScaleBitmap( BitmapEx const & aBitmap, const long aStandardSize ); |
440 | |
441 | /// populate from a canvas implementation |
442 | bool Create( |
443 | const css::uno::Reference< css::rendering::XBitmapCanvas > &xBitmapCanvas, |
444 | const Size &rSize ); |
445 | |
446 | void setAlphaFrom( sal_uInt8 cIndexFrom, sal_Int8 nAlphaTo ); |
447 | |
448 | void AdjustTransparency( sal_uInt8 cTrans ); |
449 | |
450 | void CombineMaskOr(Color maskColor, sal_uInt8 nTol); |
451 | |
452 | /** |
453 | * Retrieves the color model data we need for the XImageConsumer stuff. |
454 | */ |
455 | void GetColorModel(css::uno::Sequence< sal_Int32 >& rRGBPalette, |
456 | sal_uInt32& rnRedMask, sal_uInt32& rnGreenMask, sal_uInt32& rnBlueMask, sal_uInt32& rnAlphaMask, sal_uInt32& rnTransparencyIndex, |
457 | sal_uInt32& rnWidth, sal_uInt32& rnHeight, sal_uInt8& rnBitCount); |
458 | |
459 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) std::shared_ptr<SalBitmap> const & ImplGetBitmapSalBitmap() const { return maBitmap.ImplGetSalBitmap(); } |
460 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) std::shared_ptr<SalBitmap> const & ImplGetMaskSalBitmap() const { return maMask.ImplGetSalBitmap(); } |
461 | |
462 | |
463 | private: |
464 | friend class ImpGraphic; |
465 | friend class OutputDevice; |
466 | friend bool VCL_DLLPUBLIC__attribute__ ((visibility("default"))) WriteDIBBitmapEx(const BitmapEx& rSource, SvStream& rOStm); |
467 | friend bool VCL_DLLPUBLIC__attribute__ ((visibility("default"))) ReadRawDIB(BitmapEx& rTarget, const unsigned char* pBuf, |
468 | const ScanlineFormat nFormat, |
469 | const int nHeight, |
470 | const int nStride); |
471 | |
472 | void loadFromIconTheme( const OUString& rIconName ); |
473 | |
474 | Bitmap maBitmap; |
475 | Bitmap maMask; |
476 | Size maBitmapSize; |
477 | Color maTransparentColor; |
478 | TransparentType meTransparent; |
479 | bool mbAlpha; |
480 | |
481 | }; |
482 | |
483 | |
484 | /** Create a blend frame as BitmapEx |
485 | |
486 | @param nAlpha |
487 | The blend value defines how strong the frame will be blended with the |
488 | existing content, 255 == full coverage, 0 == no frame will be drawn |
489 | |
490 | @param aColorTopLeft, aColorBottomRight |
491 | The colors defining the frame. These colors are linearly interpolated from |
492 | aColorTopLeft and aColorBottomRight using the width and height of the area |
493 | |
494 | @param rSize |
495 | The size of the frame in pixels |
496 | */ |
497 | BitmapEx VCL_DLLPUBLIC__attribute__ ((visibility("default"))) createBlendFrame( |
498 | const Size& rSize, |
499 | sal_uInt8 nAlpha, |
500 | Color aColorTopLeft, |
501 | Color aColorBottomRight); |
502 | |
503 | |
504 | /** Create a blend frame as BitmapEx |
505 | |
506 | @param nAlpha |
507 | The blend value defines how strong the frame will be blended with the |
508 | existing content, 255 == full coverage, 0 == no frame will be drawn |
509 | |
510 | @param aColorTopLeft, aColorBottomRight, aColorTopRight, aColorBottomLeft |
511 | The colors defining the frame. |
512 | |
513 | @param rSize |
514 | The size of the frame in pixels |
515 | */ |
516 | BitmapEx createBlendFrame( |
517 | const Size& rSize, |
518 | sal_uInt8 nAlpha, |
519 | Color aColorTopLeft, |
520 | Color aColorTopRight, |
521 | Color aColorBottomRight, |
522 | Color aColorBottomLeft); |
523 | |
524 | #endif // INCLUDED_VCL_BITMAPEX_HXX |
525 | |
526 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_VCL_BITMAP_HXX |
21 | #define INCLUDED_VCL_BITMAP_HXX |
22 | |
23 | #include <tools/solar.h> |
24 | #include <vcl/checksum.hxx> |
25 | #include <vcl/dllapi.h> |
26 | #include <vcl/mapmod.hxx> |
27 | #include <vcl/region.hxx> |
28 | #include <vcl/scopedbitmapaccess.hxx> |
29 | #include <o3tl/typed_flags_set.hxx> |
30 | #include <memory> |
31 | |
32 | class Color; |
33 | |
34 | template <typename Arg, typename Ret> class Link; |
35 | |
36 | enum class BmpMirrorFlags |
37 | { |
38 | NONE = 0x00, |
39 | Horizontal = 0x01, |
40 | Vertical = 0x02, |
41 | }; |
42 | |
43 | namespace o3tl |
44 | { |
45 | template<> struct typed_flags<BmpMirrorFlags> : is_typed_flags<BmpMirrorFlags, 0x03> {}; |
46 | } |
47 | |
48 | enum class BmpScaleFlag |
49 | { |
50 | // Try to preferably use these. |
51 | Default, |
52 | Fast, |
53 | BestQuality, |
54 | // Specific algorithms, use only if you really need to (mainly used for tests) |
55 | NearestNeighbor, |
56 | Interpolate, // fast, integer bilinear |
57 | Lanczos, |
58 | BiCubic, |
59 | BiLinear, |
60 | Super // bilinear interpolation when supersampling and averaging when subsampling under certain scale |
61 | }; |
62 | |
63 | #define BMP_COL_TRANSColor( 252, 3, 251 ) Color( 252, 3, 251 ) |
64 | |
65 | enum class BmpConversion |
66 | { |
67 | NNONE, |
68 | N1BitThreshold, |
69 | N4BitGreys, |
70 | N4BitColors, |
71 | N8BitGreys, |
72 | N8BitColors, |
73 | N24Bit, |
74 | N32Bit, |
75 | N8BitTrans, |
76 | N8BitNoConversion // make 8bit without color conversion (e.g. take the red channel) |
77 | }; |
78 | |
79 | enum class BmpCombine |
80 | { |
81 | Or, And |
82 | }; |
83 | |
84 | class BitmapInfoAccess; |
85 | class BitmapReadAccess; |
86 | class BitmapWriteAccess; |
87 | class BitmapPalette; |
88 | class GDIMetaFile; |
89 | class AlphaMask; |
90 | class OutputDevice; |
91 | class SalBitmap; |
92 | |
93 | struct BitmapSystemData |
94 | { |
95 | #if defined(_WIN32) |
96 | void* pDIB; // device independent byte buffer |
97 | #elif defined( MACOSX ) || defined( IOS ) |
98 | // Nothing needed, apparently |
99 | #else |
100 | void* aPixmap; |
101 | #endif |
102 | int mnWidth; |
103 | int mnHeight; |
104 | }; |
105 | |
106 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VCL_DLLPUBLIC__attribute__ ((visibility("default"))) Bitmap |
107 | { |
108 | public: |
109 | |
110 | Bitmap(); |
111 | Bitmap( const Bitmap& rBitmap ); |
112 | Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal = nullptr ); |
113 | explicit Bitmap( std::shared_ptr<SalBitmap> const & xSalBitmap ); |
114 | virtual ~Bitmap(); |
115 | |
116 | Bitmap& operator=( const Bitmap& rBitmap ); |
117 | Bitmap& operator=( Bitmap&& rBitmap ) noexcept; |
118 | inline bool operator!() const; |
119 | bool operator==( const Bitmap& rBitmap ) const; |
120 | bool operator!=( const Bitmap& rBitmap ) const { return !operator==(rBitmap); } |
121 | |
122 | inline bool IsEmpty() const; |
123 | void SetEmpty(); |
124 | |
125 | inline const MapMode& GetPrefMapMode() const; |
126 | inline void SetPrefMapMode( const MapMode& rMapMode ); |
127 | |
128 | inline const Size& GetPrefSize() const; |
129 | inline void SetPrefSize( const Size& rSize ); |
130 | |
131 | Size GetSizePixel() const; |
132 | |
133 | sal_uInt16 GetBitCount() const; |
134 | inline sal_Int64 GetColorCount() const; |
135 | inline sal_uLong GetSizeBytes() const; |
136 | bool HasGreyPalette8Bit() const; |
137 | bool HasGreyPaletteAny() const; |
138 | /** get system dependent bitmap data |
139 | |
140 | @param rData |
141 | The system dependent BitmapSystemData structure to be filled |
142 | |
143 | @return true if the bitmap has a valid system object (e.g. not empty) |
144 | */ |
145 | bool GetSystemData( BitmapSystemData& rData ) const; |
146 | |
147 | BitmapChecksum GetChecksum() const; |
148 | |
149 | Bitmap CreateDisplayBitmap( OutputDevice* pDisplay ) const; |
150 | |
151 | static const BitmapPalette& |
152 | GetGreyPalette( int nEntries ); |
153 | |
154 | public: |
155 | |
156 | /** Convert bitmap format |
157 | |
158 | @param eConversion |
159 | The format this bitmap should be converted to. |
160 | |
161 | @return true the conversion was completed successfully. |
162 | */ |
163 | bool Convert( BmpConversion eConversion ); |
164 | |
165 | /** Apply a Floyd dither algorithm to the bitmap |
166 | |
167 | This method dithers the bitmap inplace, i.e. a true color |
168 | bitmap is converted to a paletted bitmap, reducing the color |
169 | deviation by error diffusion. |
170 | |
171 | */ |
172 | bool Dither(); |
173 | |
174 | /** Crop the bitmap |
175 | |
176 | @param rRectPixel |
177 | A rectangle specifying the crop amounts on all four sides of |
178 | the bitmap. If the upper left corner of the bitmap is assigned |
179 | (0,0), then this method cuts out the given rectangle from the |
180 | bitmap. Note that the rectangle is clipped to the bitmap's |
181 | dimension, i.e. negative left,top rectangle coordinates or |
182 | exceeding width or height is ignored. |
183 | |
184 | @return true cropping was performed successfully. If |
185 | nothing had to be cropped, because e.g. the crop rectangle |
186 | included the bitmap, false is returned, too! |
187 | */ |
188 | bool Crop( const tools::Rectangle& rRectPixel ); |
189 | |
190 | /** Expand the bitmap by pixel padding |
191 | |
192 | @param nDX |
193 | Number of pixel to pad at the right border of the bitmap |
194 | |
195 | @param nDY |
196 | Number of scanlines to pad at the bottom border of the bitmap |
197 | |
198 | @param pInitColor |
199 | Color to use for padded pixel |
200 | |
201 | @return true, if padding was performed successfully. false is |
202 | not only returned when the operation failed, but also if |
203 | nothing had to be done, e.g. because nDX and nDY were zero. |
204 | */ |
205 | bool Expand( |
206 | sal_uLong nDX, sal_uLong nDY, |
207 | const Color* pInitColor = nullptr ); |
208 | |
209 | /** Copy a rectangular area from another bitmap |
210 | |
211 | @param rRectDst |
212 | Destination rectangle in this bitmap. This is clipped to the |
213 | bitmap dimensions. |
214 | |
215 | @param rRectSrc |
216 | Source rectangle in pBmpSrc. This is clipped to the source |
217 | bitmap dimensions. Note further that no scaling takes place |
218 | during this copy operation, i.e. only the minimum of source |
219 | and destination rectangle's width and height are used. |
220 | |
221 | @param pBmpSrc |
222 | The source bitmap to copy from. If this argument is NULL, or |
223 | equal to the object this method is called on, copying takes |
224 | place within the same bitmap. |
225 | |
226 | @return true, if the operation completed successfully. false |
227 | is not only returned when the operation failed, but also if |
228 | nothing had to be done, e.g. because one of the rectangles are |
229 | empty. |
230 | */ |
231 | bool CopyPixel( |
232 | const tools::Rectangle& rRectDst, |
233 | const tools::Rectangle& rRectSrc, |
234 | const Bitmap* pBmpSrc = nullptr ); |
235 | |
236 | bool CopyPixel_AlphaOptimized( |
237 | const tools::Rectangle& rRectDst, |
238 | const tools::Rectangle& rRectSrc, |
239 | const Bitmap* pBmpSrc ); |
240 | |
241 | /** Perform boolean operations with another bitmap |
242 | |
243 | @param rMask |
244 | The mask bitmap in the selected combine operation |
245 | |
246 | @param eCombine |
247 | The combine operation to perform on the bitmap |
248 | |
249 | @return true, if the operation was completed successfully. |
250 | */ |
251 | bool CombineSimple( |
252 | const Bitmap& rMask, |
253 | BmpCombine eCombine ); |
254 | |
255 | /** Alpha-blend the given bitmap against a specified uniform |
256 | background color. |
257 | |
258 | @attention This method might convert paletted bitmaps to |
259 | truecolor, to be able to represent every necessary color. Note |
260 | that during alpha blending, lots of colors not originally |
261 | included in the bitmap can be generated. |
262 | |
263 | @param rAlpha |
264 | Alpha mask to blend with |
265 | |
266 | @param rBackgroundColor |
267 | Background color to use for every pixel during alpha blending |
268 | |
269 | @return true, if blending was successful, false otherwise |
270 | */ |
271 | bool Blend( |
272 | const AlphaMask& rAlpha, |
273 | const Color& rBackgroundColor ); |
274 | |
275 | /** Fill the entire bitmap with the given color |
276 | |
277 | @param rFillColor |
278 | Color value to use for filling |
279 | |
280 | @return true, if the operation was completed successfully. |
281 | */ |
282 | bool Erase( const Color& rFillColor ); |
283 | |
284 | /** Perform the Invert operation on every pixel |
285 | |
286 | @return true, if the operation was completed successfully. |
287 | */ |
288 | bool Invert(); |
289 | |
290 | /** Mirror the bitmap |
291 | |
292 | @param nMirrorFlags |
293 | About which axis (horizontal, vertical, or both) to mirror |
294 | |
295 | @return true, if the operation was completed successfully. |
296 | */ |
297 | bool Mirror( BmpMirrorFlags nMirrorFlags ); |
298 | |
299 | /** Scale the bitmap |
300 | |
301 | @param rNewSize |
302 | The resulting size of the scaled bitmap |
303 | |
304 | @param nScaleFlag |
305 | The algorithm to be used for scaling |
306 | |
307 | @return true, if the operation was completed successfully. |
308 | */ |
309 | bool Scale( const Size& rNewSize, BmpScaleFlag nScaleFlag = BmpScaleFlag::Default ); |
310 | |
311 | /** Scale the bitmap |
312 | |
313 | @param rScaleX |
314 | The scale factor in x direction. |
315 | |
316 | @param rScaleY |
317 | The scale factor in y direction. |
318 | |
319 | @param nScaleFlag |
320 | Method of scaling - it is recommended that either BmpScaleFlag::Default or BmpScaleFlag::BestQuality be used. |
321 | |
322 | @return true, if the operation was completed successfully. |
323 | */ |
324 | bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag = BmpScaleFlag::Default ); |
325 | |
326 | /** |
327 | Returns true if bitmap scaling is considered to be fast. |
328 | |
329 | Currently this returns true if OpenGL is used for scaling, otherwise false (CPU scaling is slower). |
330 | |
331 | @since 4.5 |
332 | */ |
333 | static bool HasFastScale(); |
334 | |
335 | // Adapt the BitCount of rNew to BitCount of total, including grey or color palette |
336 | // Can be used to create alpha/mask bitmaps after their processing in 24bit |
337 | void AdaptBitCount(Bitmap& rNew) const; |
338 | |
339 | /** Rotate bitmap by the specified angle |
340 | |
341 | @param nAngle10 |
342 | The rotation angle in tenth of a degree. The bitmap is always rotated around its center. |
343 | |
344 | @param rFillColor |
345 | The color to use for filling blank areas. During rotation, the |
346 | bitmap is enlarged such that the whole rotation result fits |
347 | in. The empty spaces around that rotated original bitmap are |
348 | then filled with this color. |
349 | |
350 | @return true, if the operation was completed successfully. |
351 | */ |
352 | bool Rotate( long nAngle10, const Color& rFillColor ); |
353 | |
354 | /** Create on-off mask from bitmap |
355 | |
356 | This method creates a bitmask from the bitmap, where every |
357 | pixel that equals rTransColor is set transparent, the rest |
358 | opaque. |
359 | |
360 | @param rTransColor |
361 | Color value where the bitmask should be transparent |
362 | |
363 | @param nTol |
364 | Tolerance value. Specifies the maximal difference between |
365 | rTransColor and the individual pixel values, such that the |
366 | corresponding pixel is still regarded as transparent. |
367 | |
368 | @return the resulting bitmask. |
369 | */ |
370 | Bitmap CreateMask( const Color& rTransColor, sal_uInt8 nTol = 0 ) const; |
371 | |
372 | /** Create region of similar colors in a given rectangle |
373 | |
374 | @param rColor |
375 | All pixel which have this color are included in the calculated region |
376 | |
377 | @param rRect |
378 | The rectangle within which matching pixel are looked for. This |
379 | rectangle is always clipped to the bitmap dimensions. |
380 | |
381 | @return the generated region. |
382 | */ |
383 | vcl::Region CreateRegion( const Color& rColor, const tools::Rectangle& rRect ) const; |
384 | |
385 | /** Replace all pixel where the given mask is on with the specified color |
386 | |
387 | @param rMask |
388 | Mask specifying which pixel should be replaced |
389 | |
390 | @param rReplaceColor |
391 | Color to be placed in all changed pixel |
392 | |
393 | @return true, if the operation was completed successfully. |
394 | */ |
395 | bool Replace( const Bitmap& rMask, const Color& rReplaceColor ); |
396 | |
397 | /** Merge bitmap with given background color according to specified alpha mask |
398 | |
399 | @param rAlpha |
400 | Alpha mask specifying the amount of background color to merge in |
401 | |
402 | @param rMergeColor |
403 | Background color to be used for merging |
404 | |
405 | @return true, if the operation was completed successfully. |
406 | */ |
407 | bool Replace( const AlphaMask& rAlpha, const Color& rMergeColor ); |
408 | |
409 | /** Replace all pixel having the search color with the specified color |
410 | |
411 | @param rSearchColor |
412 | Color specifying which pixel should be replaced |
413 | |
414 | @param rReplaceColor |
415 | Color to be placed in all changed pixel |
416 | |
417 | @param nTol |
418 | Tolerance value. Specifies the maximal difference between |
419 | rSearchColor and the individual pixel values, such that the |
420 | corresponding pixel is still regarded a match. |
421 | |
422 | @return true, if the operation was completed successfully. |
423 | */ |
424 | bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol = 0 ); |
425 | |
426 | /** Replace all pixel having one the search colors with the corresponding replace color |
427 | |
428 | @param pSearchColors |
429 | Array of colors specifying which pixel should be replaced |
430 | |
431 | @param rReplaceColors |
432 | Array of colors to be placed in all changed pixel |
433 | |
434 | @param nColorCount |
435 | Size of the aforementioned color arrays |
436 | |
437 | @param pTols |
438 | Tolerance value. Specifies the maximal difference between |
439 | pSearchColor colors and the individual pixel values, such that |
440 | the corresponding pixel is still regarded a match. |
441 | |
442 | @return true, if the operation was completed successfully. |
443 | */ |
444 | bool Replace( |
445 | const Color* pSearchColors, |
446 | const Color* rReplaceColors, |
447 | sal_uLong nColorCount, |
448 | sal_uInt8 const * pTols ); |
449 | |
450 | /** Convert the bitmap to a meta file |
451 | |
452 | This works by putting continuous areas of the same color into |
453 | polygons painted in this color, by tracing the area's bounding |
454 | line. |
455 | |
456 | @param rMtf |
457 | The resulting meta file |
458 | |
459 | @param cReduce |
460 | If non-null, minimal size of bound rects for individual polygons. Smaller ones are ignored. |
461 | |
462 | @param pProgress |
463 | A callback for showing the progress of the vectorization |
464 | */ |
465 | void Vectorize( |
466 | GDIMetaFile& rMtf, |
467 | sal_uInt8 cReduce, |
468 | const Link<long,void>* pProgress ); |
469 | |
470 | /** Change various global color characteristics |
471 | |
472 | @param nLuminancePercent |
473 | Percent of luminance change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
474 | |
475 | @param nContrastPercent |
476 | Percent of contrast change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
477 | |
478 | @param nChannelRPercent |
479 | Percent of red channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
480 | |
481 | @param nChannelGPercent |
482 | Percent of green channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
483 | |
484 | @param nChannelBPercent |
485 | Percent of blue channel change, valid range [-100,100]. Values outside this range are clipped to the valid range. |
486 | |
487 | @param fGamma |
488 | Exponent of the gamma function applied to the bitmap. The |
489 | value 1.0 results in no change, the valid range is |
490 | (0.0,10.0]. Values outside this range are regarded as 1.0. |
491 | |
492 | @param bInvert |
493 | If true, invert the channel values with the logical 'not' operator |
494 | |
495 | @param msoBrightness |
496 | Use the same formula for brightness as used by MSOffice. |
497 | |
498 | @return true, if the operation was completed successfully. |
499 | */ |
500 | bool Adjust( |
501 | short nLuminancePercent, |
502 | short nContrastPercent = 0, |
503 | short nChannelRPercent = 0, |
504 | short nChannelGPercent = 0, |
505 | short nChannelBPercent = 0, |
506 | double fGamma = 1.0, |
507 | bool bInvert = false, |
508 | bool msoBrightness = false ); |
509 | |
510 | public: |
511 | /** ReassignWithSize and recalculate bitmap. |
512 | |
513 | ReassignWithSizes the bitmap, and recalculates the bitmap size based on the new bitmap. |
514 | |
515 | @param rBitmap Bitmap to reassign and use for size calculation |
516 | */ |
517 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ReassignWithSize(const Bitmap& rBitmap); |
518 | |
519 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImplMakeUnique(); |
520 | const std::shared_ptr<SalBitmap>& ImplGetSalBitmap() const { return mxSalBmp; } |
521 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImplSetSalBitmap( const std::shared_ptr<SalBitmap>& xImpBmp ); |
522 | |
523 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool ImplMakeGreyscales( sal_uInt16 nGreyscales ); |
524 | |
525 | public: |
526 | |
527 | BitmapInfoAccess* AcquireInfoAccess(); |
528 | BitmapReadAccess* AcquireReadAccess(); |
529 | BitmapWriteAccess* AcquireWriteAccess(); |
530 | static void ReleaseAccess( BitmapInfoAccess* pAccess ); |
531 | |
532 | typedef vcl::ScopedBitmapAccess<BitmapReadAccess, Bitmap, &Bitmap::AcquireReadAccess> ScopedReadAccess; |
533 | typedef vcl::ScopedBitmapAccess<BitmapInfoAccess, Bitmap, &Bitmap::AcquireInfoAccess> ScopedInfoAccess; |
534 | |
535 | private: |
536 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool ImplConvertUp(sal_uInt16 nBitCount, Color const* pExtColor = nullptr); |
537 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool ImplConvertDown(sal_uInt16 nBitCount, Color const* pExtColor = nullptr); |
538 | |
539 | private: |
540 | std::shared_ptr<SalBitmap> mxSalBmp; |
541 | MapMode maPrefMapMode; |
542 | Size maPrefSize; |
543 | |
544 | }; |
545 | |
546 | inline bool Bitmap::operator!() const |
547 | { |
548 | return( mxSalBmp == nullptr ); |
549 | } |
550 | |
551 | inline bool Bitmap::IsEmpty() const |
552 | { |
553 | return( mxSalBmp == nullptr ); |
554 | } |
555 | |
556 | inline const MapMode& Bitmap::GetPrefMapMode() const |
557 | { |
558 | return maPrefMapMode; |
559 | } |
560 | |
561 | inline void Bitmap::SetPrefMapMode( const MapMode& rMapMode ) |
562 | { |
563 | maPrefMapMode = rMapMode; |
564 | } |
565 | |
566 | inline const Size& Bitmap::GetPrefSize() const |
567 | { |
568 | return maPrefSize; |
569 | } |
570 | |
571 | inline void Bitmap::SetPrefSize( const Size& rSize ) |
572 | { |
573 | maPrefSize = rSize; |
574 | } |
575 | |
576 | inline sal_Int64 Bitmap::GetColorCount() const |
577 | { |
578 | return sal_Int64(1) << sal_Int64(GetBitCount()); |
579 | } |
580 | |
581 | inline sal_uLong Bitmap::GetSizeBytes() const |
582 | { |
583 | const Size aSizePix( GetSizePixel() ); |
584 | return( ( static_cast<sal_uLong>(aSizePix.Width()) * aSizePix.Height() * GetBitCount() ) >> 3 ); |
585 | } |
586 | |
587 | #endif // INCLUDED_VCL_BITMAP_HXX |
588 | |
589 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | // shared_ptr and weak_ptr implementation -*- C++ -*- |
2 | |
3 | // Copyright (C) 2007-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 | // GCC Note: Based on files from version 1.32.0 of the Boost library. |
26 | |
27 | // shared_count.hpp |
28 | // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. |
29 | |
30 | // shared_ptr.hpp |
31 | // Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes. |
32 | // Copyright (C) 2001, 2002, 2003 Peter Dimov |
33 | |
34 | // weak_ptr.hpp |
35 | // Copyright (C) 2001, 2002, 2003 Peter Dimov |
36 | |
37 | // enable_shared_from_this.hpp |
38 | // Copyright (C) 2002 Peter Dimov |
39 | |
40 | // Distributed under the Boost Software License, Version 1.0. (See |
41 | // accompanying file LICENSE_1_0.txt or copy at |
42 | // http://www.boost.org/LICENSE_1_0.txt) |
43 | |
44 | /** @file |
45 | * This is an internal header file, included by other library headers. |
46 | * Do not attempt to use it directly. @headername{memory} |
47 | */ |
48 | |
49 | #ifndef _SHARED_PTR_H1 |
50 | #define _SHARED_PTR_H1 1 |
51 | |
52 | #include <bits/shared_ptr_base.h> |
53 | |
54 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
55 | { |
56 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
57 | |
58 | /** |
59 | * @addtogroup pointer_abstractions |
60 | * @{ |
61 | */ |
62 | |
63 | // 20.7.2.2.11 shared_ptr I/O |
64 | |
65 | /// Write the stored pointer to an ostream. |
66 | /// @relates shared_ptr |
67 | template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp> |
68 | inline std::basic_ostream<_Ch, _Tr>& |
69 | operator<<(std::basic_ostream<_Ch, _Tr>& __os, |
70 | const __shared_ptr<_Tp, _Lp>& __p) |
71 | { |
72 | __os << __p.get(); |
73 | return __os; |
74 | } |
75 | |
76 | template<typename _Del, typename _Tp, _Lock_policy _Lp> |
77 | inline _Del* |
78 | get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept |
79 | { |
80 | #if __cpp_rtti199711L |
81 | return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del))); |
82 | #else |
83 | return 0; |
84 | #endif |
85 | } |
86 | |
87 | /// 20.7.2.2.10 shared_ptr get_deleter |
88 | |
89 | /// If `__p` has a deleter of type `_Del`, return a pointer to it. |
90 | /// @relates shared_ptr |
91 | template<typename _Del, typename _Tp> |
92 | inline _Del* |
93 | get_deleter(const shared_ptr<_Tp>& __p) noexcept |
94 | { |
95 | #if __cpp_rtti199711L |
96 | return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del))); |
97 | #else |
98 | return 0; |
99 | #endif |
100 | } |
101 | |
102 | /** |
103 | * @brief A smart pointer with reference-counted copy semantics. |
104 | * |
105 | * A `shared_ptr` object is either empty or _owns_ a pointer passed |
106 | * to the constructor. Copies of a `shared_ptr` share ownership of |
107 | * the same pointer. When the last `shared_ptr` that owns the pointer |
108 | * is destroyed or reset, the owned pointer is freed (either by `delete` |
109 | * or by invoking a custom deleter that was passed to the constructor). |
110 | * |
111 | * A `shared_ptr` also stores another pointer, which is usually |
112 | * (but not always) the same pointer as it owns. The stored pointer |
113 | * can be retrieved by calling the `get()` member function. |
114 | * |
115 | * The equality and relational operators for `shared_ptr` only compare |
116 | * the stored pointer returned by `get()`, not the owned pointer. |
117 | * To test whether two `shared_ptr` objects share ownership of the same |
118 | * pointer see `std::shared_ptr::owner_before` and `std::owner_less`. |
119 | */ |
120 | template<typename _Tp> |
121 | class shared_ptr : public __shared_ptr<_Tp> |
122 | { |
123 | template<typename... _Args> |
124 | using _Constructible = typename enable_if< |
125 | is_constructible<__shared_ptr<_Tp>, _Args...>::value |
126 | >::type; |
127 | |
128 | template<typename _Arg> |
129 | using _Assignable = typename enable_if< |
130 | is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr& |
131 | >::type; |
132 | |
133 | public: |
134 | |
135 | /// The type pointed to by the stored pointer, remove_extent_t<_Tp> |
136 | using element_type = typename __shared_ptr<_Tp>::element_type; |
137 | |
138 | #if __cplusplus201703L >= 201703L |
139 | # define __cpp_lib_shared_ptr_weak_type201606 201606 |
140 | /// The corresponding weak_ptr type for this shared_ptr |
141 | using weak_type = weak_ptr<_Tp>; |
142 | #endif |
143 | /** |
144 | * @brief Construct an empty %shared_ptr. |
145 | * @post use_count()==0 && get()==0 |
146 | */ |
147 | constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { } |
148 | |
149 | shared_ptr(const shared_ptr&) noexcept = default; ///< Copy constructor |
150 | |
151 | /** |
152 | * @brief Construct a %shared_ptr that owns the pointer @a __p. |
153 | * @param __p A pointer that is convertible to element_type*. |
154 | * @post use_count() == 1 && get() == __p |
155 | * @throw std::bad_alloc, in which case @c delete @a __p is called. |
156 | */ |
157 | template<typename _Yp, typename = _Constructible<_Yp*>> |
158 | explicit |
159 | shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { } |
160 | |
161 | /** |
162 | * @brief Construct a %shared_ptr that owns the pointer @a __p |
163 | * and the deleter @a __d. |
164 | * @param __p A pointer. |
165 | * @param __d A deleter. |
166 | * @post use_count() == 1 && get() == __p |
167 | * @throw std::bad_alloc, in which case @a __d(__p) is called. |
168 | * |
169 | * Requirements: _Deleter's copy constructor and destructor must |
170 | * not throw |
171 | * |
172 | * __shared_ptr will release __p by calling __d(__p) |
173 | */ |
174 | template<typename _Yp, typename _Deleter, |
175 | typename = _Constructible<_Yp*, _Deleter>> |
176 | shared_ptr(_Yp* __p, _Deleter __d) |
177 | : __shared_ptr<_Tp>(__p, std::move(__d)) { } |
178 | |
179 | /** |
180 | * @brief Construct a %shared_ptr that owns a null pointer |
181 | * and the deleter @a __d. |
182 | * @param __p A null pointer constant. |
183 | * @param __d A deleter. |
184 | * @post use_count() == 1 && get() == __p |
185 | * @throw std::bad_alloc, in which case @a __d(__p) is called. |
186 | * |
187 | * Requirements: _Deleter's copy constructor and destructor must |
188 | * not throw |
189 | * |
190 | * The last owner will call __d(__p) |
191 | */ |
192 | template<typename _Deleter> |
193 | shared_ptr(nullptr_t __p, _Deleter __d) |
194 | : __shared_ptr<_Tp>(__p, std::move(__d)) { } |
195 | |
196 | /** |
197 | * @brief Construct a %shared_ptr that owns the pointer @a __p |
198 | * and the deleter @a __d. |
199 | * @param __p A pointer. |
200 | * @param __d A deleter. |
201 | * @param __a An allocator. |
202 | * @post use_count() == 1 && get() == __p |
203 | * @throw std::bad_alloc, in which case @a __d(__p) is called. |
204 | * |
205 | * Requirements: _Deleter's copy constructor and destructor must |
206 | * not throw _Alloc's copy constructor and destructor must not |
207 | * throw. |
208 | * |
209 | * __shared_ptr will release __p by calling __d(__p) |
210 | */ |
211 | template<typename _Yp, typename _Deleter, typename _Alloc, |
212 | typename = _Constructible<_Yp*, _Deleter, _Alloc>> |
213 | shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) |
214 | : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { } |
215 | |
216 | /** |
217 | * @brief Construct a %shared_ptr that owns a null pointer |
218 | * and the deleter @a __d. |
219 | * @param __p A null pointer constant. |
220 | * @param __d A deleter. |
221 | * @param __a An allocator. |
222 | * @post use_count() == 1 && get() == __p |
223 | * @throw std::bad_alloc, in which case @a __d(__p) is called. |
224 | * |
225 | * Requirements: _Deleter's copy constructor and destructor must |
226 | * not throw _Alloc's copy constructor and destructor must not |
227 | * throw. |
228 | * |
229 | * The last owner will call __d(__p) |
230 | */ |
231 | template<typename _Deleter, typename _Alloc> |
232 | shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) |
233 | : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { } |
234 | |
235 | // Aliasing constructor |
236 | |
237 | /** |
238 | * @brief Constructs a `shared_ptr` instance that stores `__p` |
239 | * and shares ownership with `__r`. |
240 | * @param __r A `shared_ptr`. |
241 | * @param __p A pointer that will remain valid while `*__r` is valid. |
242 | * @post `get() == __p && use_count() == __r.use_count()` |
243 | * |
244 | * This can be used to construct a `shared_ptr` to a sub-object |
245 | * of an object managed by an existing `shared_ptr`. The complete |
246 | * object will remain valid while any `shared_ptr` owns it, even |
247 | * if they don't store a pointer to the complete object. |
248 | * |
249 | * @code |
250 | * shared_ptr<pair<int,int>> pii(new pair<int,int>()); |
251 | * shared_ptr<int> pi(pii, &pii->first); |
252 | * assert(pii.use_count() == 2); |
253 | * @endcode |
254 | */ |
255 | template<typename _Yp> |
256 | shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept |
257 | : __shared_ptr<_Tp>(__r, __p) { } |
258 | |
259 | #if __cplusplus201703L > 201703L |
260 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
261 | // 2996. Missing rvalue overloads for shared_ptr operations |
262 | /** |
263 | * @brief Constructs a `shared_ptr` instance that stores `__p` |
264 | * and shares ownership with `__r`. |
265 | * @param __r A `shared_ptr`. |
266 | * @param __p A pointer that will remain valid while `*__r` is valid. |
267 | * @post `get() == __p && !__r.use_count() && !__r.get()` |
268 | * |
269 | * This can be used to construct a `shared_ptr` to a sub-object |
270 | * of an object managed by an existing `shared_ptr`. The complete |
271 | * object will remain valid while any `shared_ptr` owns it, even |
272 | * if they don't store a pointer to the complete object. |
273 | * |
274 | * @code |
275 | * shared_ptr<pair<int,int>> pii(new pair<int,int>()); |
276 | * shared_ptr<int> pi1(pii, &pii->first); |
277 | * assert(pii.use_count() == 2); |
278 | * shared_ptr<int> pi2(std::move(pii), &pii->second); |
279 | * assert(pii.use_count() == 0); |
280 | * @endcode |
281 | */ |
282 | template<typename _Yp> |
283 | shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept |
284 | : __shared_ptr<_Tp>(std::move(__r), __p) { } |
285 | #endif |
286 | /** |
287 | * @brief If @a __r is empty, constructs an empty %shared_ptr; |
288 | * otherwise construct a %shared_ptr that shares ownership |
289 | * with @a __r. |
290 | * @param __r A %shared_ptr. |
291 | * @post get() == __r.get() && use_count() == __r.use_count() |
292 | */ |
293 | template<typename _Yp, |
294 | typename = _Constructible<const shared_ptr<_Yp>&>> |
295 | shared_ptr(const shared_ptr<_Yp>& __r) noexcept |
296 | : __shared_ptr<_Tp>(__r) { } |
297 | |
298 | /** |
299 | * @brief Move-constructs a %shared_ptr instance from @a __r. |
300 | * @param __r A %shared_ptr rvalue. |
301 | * @post *this contains the old value of @a __r, @a __r is empty. |
302 | */ |
303 | shared_ptr(shared_ptr&& __r) noexcept |
304 | : __shared_ptr<_Tp>(std::move(__r)) { } |
305 | |
306 | /** |
307 | * @brief Move-constructs a %shared_ptr instance from @a __r. |
308 | * @param __r A %shared_ptr rvalue. |
309 | * @post *this contains the old value of @a __r, @a __r is empty. |
310 | */ |
311 | template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>> |
312 | shared_ptr(shared_ptr<_Yp>&& __r) noexcept |
313 | : __shared_ptr<_Tp>(std::move(__r)) { } |
314 | |
315 | /** |
316 | * @brief Constructs a %shared_ptr that shares ownership with @a __r |
317 | * and stores a copy of the pointer stored in @a __r. |
318 | * @param __r A weak_ptr. |
319 | * @post use_count() == __r.use_count() |
320 | * @throw bad_weak_ptr when __r.expired(), |
321 | * in which case the constructor has no effect. |
322 | */ |
323 | template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>> |
324 | explicit shared_ptr(const weak_ptr<_Yp>& __r) |
325 | : __shared_ptr<_Tp>(__r) { } |
326 | |
327 | #if _GLIBCXX_USE_DEPRECATED1 |
328 | #pragma GCC diagnostic push |
329 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
330 | template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>> |
331 | shared_ptr(auto_ptr<_Yp>&& __r); |
332 | #pragma GCC diagnostic pop |
333 | #endif |
334 | |
335 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
336 | // 2399. shared_ptr's constructor from unique_ptr should be constrained |
337 | template<typename _Yp, typename _Del, |
338 | typename = _Constructible<unique_ptr<_Yp, _Del>>> |
339 | shared_ptr(unique_ptr<_Yp, _Del>&& __r) |
340 | : __shared_ptr<_Tp>(std::move(__r)) { } |
341 | |
342 | #if __cplusplus201703L <= 201402L && _GLIBCXX_USE_DEPRECATED1 |
343 | // This non-standard constructor exists to support conversions that |
344 | // were possible in C++11 and C++14 but are ill-formed in C++17. |
345 | // If an exception is thrown this constructor has no effect. |
346 | template<typename _Yp, typename _Del, |
347 | _Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0> |
348 | shared_ptr(unique_ptr<_Yp, _Del>&& __r) |
349 | : __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { } |
350 | #endif |
351 | |
352 | /** |
353 | * @brief Construct an empty %shared_ptr. |
354 | * @post use_count() == 0 && get() == nullptr |
355 | */ |
356 | constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } |
357 | |
358 | shared_ptr& operator=(const shared_ptr&) noexcept = default; |
359 | |
360 | template<typename _Yp> |
361 | _Assignable<const shared_ptr<_Yp>&> |
362 | operator=(const shared_ptr<_Yp>& __r) noexcept |
363 | { |
364 | this->__shared_ptr<_Tp>::operator=(__r); |
365 | return *this; |
366 | } |
367 | |
368 | #if _GLIBCXX_USE_DEPRECATED1 |
369 | #pragma GCC diagnostic push |
370 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
371 | template<typename _Yp> |
372 | _Assignable<auto_ptr<_Yp>> |
373 | operator=(auto_ptr<_Yp>&& __r) |
374 | { |
375 | this->__shared_ptr<_Tp>::operator=(std::move(__r)); |
376 | return *this; |
377 | } |
378 | #pragma GCC diagnostic pop |
379 | #endif |
380 | |
381 | shared_ptr& |
382 | operator=(shared_ptr&& __r) noexcept |
383 | { |
384 | this->__shared_ptr<_Tp>::operator=(std::move(__r)); |
385 | return *this; |
386 | } |
387 | |
388 | template<class _Yp> |
389 | _Assignable<shared_ptr<_Yp>> |
390 | operator=(shared_ptr<_Yp>&& __r) noexcept |
391 | { |
392 | this->__shared_ptr<_Tp>::operator=(std::move(__r)); |
393 | return *this; |
394 | } |
395 | |
396 | template<typename _Yp, typename _Del> |
397 | _Assignable<unique_ptr<_Yp, _Del>> |
398 | operator=(unique_ptr<_Yp, _Del>&& __r) |
399 | { |
400 | this->__shared_ptr<_Tp>::operator=(std::move(__r)); |
401 | return *this; |
402 | } |
403 | |
404 | private: |
405 | // This constructor is non-standard, it is used by allocate_shared. |
406 | template<typename _Alloc, typename... _Args> |
407 | shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args) |
408 | : __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...) |
409 | { } |
410 | |
411 | template<typename _Yp, typename _Alloc, typename... _Args> |
412 | friend shared_ptr<_Yp> |
413 | allocate_shared(const _Alloc& __a, _Args&&... __args); |
414 | |
415 | // This constructor is non-standard, it is used by weak_ptr::lock(). |
416 | shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t) |
417 | : __shared_ptr<_Tp>(__r, std::nothrow) { } |
418 | |
419 | friend class weak_ptr<_Tp>; |
420 | }; |
421 | |
422 | #if __cpp_deduction_guides201703L >= 201606 |
423 | template<typename _Tp> |
424 | shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>; |
425 | template<typename _Tp, typename _Del> |
426 | shared_ptr(unique_ptr<_Tp, _Del>) -> shared_ptr<_Tp>; |
427 | #endif |
428 | |
429 | // 20.7.2.2.7 shared_ptr comparisons |
430 | |
431 | /// @relates shared_ptr @{ |
432 | |
433 | /// Equality operator for shared_ptr objects, compares the stored pointers |
434 | template<typename _Tp, typename _Up> |
435 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
436 | operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
437 | { return __a.get() == __b.get(); } |
438 | |
439 | /// shared_ptr comparison with nullptr |
440 | template<typename _Tp> |
441 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
442 | operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
443 | { return !__a; } |
444 | |
445 | #ifdef __cpp_lib_three_way_comparison |
446 | template<typename _Tp, typename _Up> |
447 | inline strong_ordering |
448 | operator<=>(const shared_ptr<_Tp>& __a, |
449 | const shared_ptr<_Up>& __b) noexcept |
450 | { return compare_three_way()(__a.get(), __b.get()); } |
451 | |
452 | template<typename _Tp> |
453 | inline strong_ordering |
454 | operator<=>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
455 | { |
456 | using pointer = typename shared_ptr<_Tp>::element_type*; |
457 | return compare_three_way()(__a.get(), static_cast<pointer>(nullptr)); |
458 | } |
459 | #else |
460 | /// shared_ptr comparison with nullptr |
461 | template<typename _Tp> |
462 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
463 | operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
464 | { return !__a; } |
465 | |
466 | /// Inequality operator for shared_ptr objects, compares the stored pointers |
467 | template<typename _Tp, typename _Up> |
468 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
469 | operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
470 | { return __a.get() != __b.get(); } |
471 | |
472 | /// shared_ptr comparison with nullptr |
473 | template<typename _Tp> |
474 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
475 | operator!=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
476 | { return (bool)__a; } |
477 | |
478 | /// shared_ptr comparison with nullptr |
479 | template<typename _Tp> |
480 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
481 | operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
482 | { return (bool)__a; } |
483 | |
484 | /// Relational operator for shared_ptr objects, compares the stored pointers |
485 | template<typename _Tp, typename _Up> |
486 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
487 | operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
488 | { |
489 | using _Tp_elt = typename shared_ptr<_Tp>::element_type; |
490 | using _Up_elt = typename shared_ptr<_Up>::element_type; |
491 | using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; |
492 | return less<_Vp>()(__a.get(), __b.get()); |
493 | } |
494 | |
495 | /// shared_ptr comparison with nullptr |
496 | template<typename _Tp> |
497 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
498 | operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
499 | { |
500 | using _Tp_elt = typename shared_ptr<_Tp>::element_type; |
501 | return less<_Tp_elt*>()(__a.get(), nullptr); |
502 | } |
503 | |
504 | /// shared_ptr comparison with nullptr |
505 | template<typename _Tp> |
506 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
507 | operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
508 | { |
509 | using _Tp_elt = typename shared_ptr<_Tp>::element_type; |
510 | return less<_Tp_elt*>()(nullptr, __a.get()); |
511 | } |
512 | |
513 | /// Relational operator for shared_ptr objects, compares the stored pointers |
514 | template<typename _Tp, typename _Up> |
515 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
516 | operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
517 | { return !(__b < __a); } |
518 | |
519 | /// shared_ptr comparison with nullptr |
520 | template<typename _Tp> |
521 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
522 | operator<=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
523 | { return !(nullptr < __a); } |
524 | |
525 | /// shared_ptr comparison with nullptr |
526 | template<typename _Tp> |
527 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
528 | operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
529 | { return !(__a < nullptr); } |
530 | |
531 | /// Relational operator for shared_ptr objects, compares the stored pointers |
532 | template<typename _Tp, typename _Up> |
533 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
534 | operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
535 | { return (__b < __a); } |
536 | |
537 | /// shared_ptr comparison with nullptr |
538 | template<typename _Tp> |
539 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
540 | operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
541 | { return nullptr < __a; } |
542 | |
543 | /// shared_ptr comparison with nullptr |
544 | template<typename _Tp> |
545 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
546 | operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
547 | { return __a < nullptr; } |
548 | |
549 | /// Relational operator for shared_ptr objects, compares the stored pointers |
550 | template<typename _Tp, typename _Up> |
551 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
552 | operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept |
553 | { return !(__a < __b); } |
554 | |
555 | /// shared_ptr comparison with nullptr |
556 | template<typename _Tp> |
557 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
558 | operator>=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept |
559 | { return !(__a < nullptr); } |
560 | |
561 | /// shared_ptr comparison with nullptr |
562 | template<typename _Tp> |
563 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool |
564 | operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept |
565 | { return !(nullptr < __a); } |
566 | #endif |
567 | |
568 | // 20.7.2.2.8 shared_ptr specialized algorithms. |
569 | |
570 | /// Swap overload for shared_ptr |
571 | template<typename _Tp> |
572 | inline void |
573 | swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept |
574 | { __a.swap(__b); } |
575 | |
576 | // 20.7.2.2.9 shared_ptr casts. |
577 | |
578 | /// Convert type of `shared_ptr`, via `static_cast` |
579 | template<typename _Tp, typename _Up> |
580 | inline shared_ptr<_Tp> |
581 | static_pointer_cast(const shared_ptr<_Up>& __r) noexcept |
582 | { |
583 | using _Sp = shared_ptr<_Tp>; |
584 | return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get())); |
585 | } |
586 | |
587 | /// Convert type of `shared_ptr`, via `const_cast` |
588 | template<typename _Tp, typename _Up> |
589 | inline shared_ptr<_Tp> |
590 | const_pointer_cast(const shared_ptr<_Up>& __r) noexcept |
591 | { |
592 | using _Sp = shared_ptr<_Tp>; |
593 | return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get())); |
594 | } |
595 | |
596 | /// Convert type of `shared_ptr`, via `dynamic_cast` |
597 | template<typename _Tp, typename _Up> |
598 | inline shared_ptr<_Tp> |
599 | dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept |
600 | { |
601 | using _Sp = shared_ptr<_Tp>; |
602 | if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) |
603 | return _Sp(__r, __p); |
604 | return _Sp(); |
605 | } |
606 | |
607 | #if __cplusplus201703L >= 201703L |
608 | /// Convert type of `shared_ptr`, via `reinterpret_cast` |
609 | template<typename _Tp, typename _Up> |
610 | inline shared_ptr<_Tp> |
611 | reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept |
612 | { |
613 | using _Sp = shared_ptr<_Tp>; |
614 | return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); |
615 | } |
616 | |
617 | #if __cplusplus201703L > 201703L |
618 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
619 | // 2996. Missing rvalue overloads for shared_ptr operations |
620 | |
621 | /// Convert type of `shared_ptr` rvalue, via `static_cast` |
622 | template<typename _Tp, typename _Up> |
623 | inline shared_ptr<_Tp> |
624 | static_pointer_cast(shared_ptr<_Up>&& __r) noexcept |
625 | { |
626 | using _Sp = shared_ptr<_Tp>; |
627 | return _Sp(std::move(__r), |
628 | static_cast<typename _Sp::element_type*>(__r.get())); |
629 | } |
630 | |
631 | /// Convert type of `shared_ptr` rvalue, via `const_cast` |
632 | template<typename _Tp, typename _Up> |
633 | inline shared_ptr<_Tp> |
634 | const_pointer_cast(shared_ptr<_Up>&& __r) noexcept |
635 | { |
636 | using _Sp = shared_ptr<_Tp>; |
637 | return _Sp(std::move(__r), |
638 | const_cast<typename _Sp::element_type*>(__r.get())); |
639 | } |
640 | |
641 | /// Convert type of `shared_ptr` rvalue, via `dynamic_cast` |
642 | template<typename _Tp, typename _Up> |
643 | inline shared_ptr<_Tp> |
644 | dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept |
645 | { |
646 | using _Sp = shared_ptr<_Tp>; |
647 | if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) |
648 | return _Sp(std::move(__r), __p); |
649 | return _Sp(); |
650 | } |
651 | |
652 | /// Convert type of `shared_ptr` rvalue, via `reinterpret_cast` |
653 | template<typename _Tp, typename _Up> |
654 | inline shared_ptr<_Tp> |
655 | reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept |
656 | { |
657 | using _Sp = shared_ptr<_Tp>; |
658 | return _Sp(std::move(__r), |
659 | reinterpret_cast<typename _Sp::element_type*>(__r.get())); |
660 | } |
661 | #endif // C++20 |
662 | #endif // C++17 |
663 | |
664 | // @} |
665 | |
666 | /** |
667 | * @brief A non-owning observer for a pointer owned by a shared_ptr |
668 | * |
669 | * A weak_ptr provides a safe alternative to a raw pointer when you want |
670 | * a non-owning reference to an object that is managed by a shared_ptr. |
671 | * |
672 | * Unlike a raw pointer, a weak_ptr can be converted to a new shared_ptr |
673 | * that shares ownership with every other shared_ptr that already owns |
674 | * the pointer. In other words you can upgrade from a non-owning "weak" |
675 | * reference to an owning shared_ptr, without having access to any of |
676 | * the existing shared_ptr objects. |
677 | * |
678 | * Also unlike a raw pointer, a weak_ptr does not become "dangling" after |
679 | * the object it points to has been destroyed. Instead, a weak_ptr |
680 | * becomes _expired_ and can no longer be converted to a shared_ptr that |
681 | * owns the freed pointer, so you cannot accidentally access the pointed-to |
682 | * object after it has been destroyed. |
683 | */ |
684 | template<typename _Tp> |
685 | class weak_ptr : public __weak_ptr<_Tp> |
686 | { |
687 | template<typename _Arg> |
688 | using _Constructible = typename enable_if< |
689 | is_constructible<__weak_ptr<_Tp>, _Arg>::value |
690 | >::type; |
691 | |
692 | template<typename _Arg> |
693 | using _Assignable = typename enable_if< |
694 | is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr& |
695 | >::type; |
696 | |
697 | public: |
698 | constexpr weak_ptr() noexcept = default; |
699 | |
700 | template<typename _Yp, |
701 | typename = _Constructible<const shared_ptr<_Yp>&>> |
702 | weak_ptr(const shared_ptr<_Yp>& __r) noexcept |
703 | : __weak_ptr<_Tp>(__r) { } |
704 | |
705 | weak_ptr(const weak_ptr&) noexcept = default; |
706 | |
707 | template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>> |
708 | weak_ptr(const weak_ptr<_Yp>& __r) noexcept |
709 | : __weak_ptr<_Tp>(__r) { } |
710 | |
711 | weak_ptr(weak_ptr&&) noexcept = default; |
712 | |
713 | template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>> |
714 | weak_ptr(weak_ptr<_Yp>&& __r) noexcept |
715 | : __weak_ptr<_Tp>(std::move(__r)) { } |
716 | |
717 | weak_ptr& |
718 | operator=(const weak_ptr& __r) noexcept = default; |
719 | |
720 | template<typename _Yp> |
721 | _Assignable<const weak_ptr<_Yp>&> |
722 | operator=(const weak_ptr<_Yp>& __r) noexcept |
723 | { |
724 | this->__weak_ptr<_Tp>::operator=(__r); |
725 | return *this; |
726 | } |
727 | |
728 | template<typename _Yp> |
729 | _Assignable<const shared_ptr<_Yp>&> |
730 | operator=(const shared_ptr<_Yp>& __r) noexcept |
731 | { |
732 | this->__weak_ptr<_Tp>::operator=(__r); |
733 | return *this; |
734 | } |
735 | |
736 | weak_ptr& |
737 | operator=(weak_ptr&& __r) noexcept = default; |
738 | |
739 | template<typename _Yp> |
740 | _Assignable<weak_ptr<_Yp>> |
741 | operator=(weak_ptr<_Yp>&& __r) noexcept |
742 | { |
743 | this->__weak_ptr<_Tp>::operator=(std::move(__r)); |
744 | return *this; |
745 | } |
746 | |
747 | shared_ptr<_Tp> |
748 | lock() const noexcept |
749 | { return shared_ptr<_Tp>(*this, std::nothrow); } |
750 | }; |
751 | |
752 | #if __cpp_deduction_guides201703L >= 201606 |
753 | template<typename _Tp> |
754 | weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>; |
755 | #endif |
756 | |
757 | // 20.7.2.3.6 weak_ptr specialized algorithms. |
758 | /// Swap overload for weak_ptr |
759 | /// @relates weak_ptr |
760 | template<typename _Tp> |
761 | inline void |
762 | swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept |
763 | { __a.swap(__b); } |
764 | |
765 | |
766 | /// Primary template owner_less |
767 | template<typename _Tp = void> |
768 | struct owner_less; |
769 | |
770 | /// Void specialization of owner_less compares either shared_ptr or weak_ptr |
771 | template<> |
772 | struct owner_less<void> : _Sp_owner_less<void, void> |
773 | { }; |
774 | |
775 | /// Partial specialization of owner_less for shared_ptr. |
776 | template<typename _Tp> |
777 | struct owner_less<shared_ptr<_Tp>> |
778 | : public _Sp_owner_less<shared_ptr<_Tp>, weak_ptr<_Tp>> |
779 | { }; |
780 | |
781 | /// Partial specialization of owner_less for weak_ptr. |
782 | template<typename _Tp> |
783 | struct owner_less<weak_ptr<_Tp>> |
784 | : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>> |
785 | { }; |
786 | |
787 | /** |
788 | * @brief Base class allowing use of member function shared_from_this. |
789 | */ |
790 | template<typename _Tp> |
791 | class enable_shared_from_this |
792 | { |
793 | protected: |
794 | constexpr enable_shared_from_this() noexcept { } |
795 | |
796 | enable_shared_from_this(const enable_shared_from_this&) noexcept { } |
797 | |
798 | enable_shared_from_this& |
799 | operator=(const enable_shared_from_this&) noexcept |
800 | { return *this; } |
801 | |
802 | ~enable_shared_from_this() { } |
803 | |
804 | public: |
805 | shared_ptr<_Tp> |
806 | shared_from_this() |
807 | { return shared_ptr<_Tp>(this->_M_weak_this); } |
808 | |
809 | shared_ptr<const _Tp> |
810 | shared_from_this() const |
811 | { return shared_ptr<const _Tp>(this->_M_weak_this); } |
812 | |
813 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
814 | #define __cpp_lib_enable_shared_from_this201603 201603 |
815 | weak_ptr<_Tp> |
816 | weak_from_this() noexcept |
817 | { return this->_M_weak_this; } |
818 | |
819 | weak_ptr<const _Tp> |
820 | weak_from_this() const noexcept |
821 | { return this->_M_weak_this; } |
822 | #endif |
823 | |
824 | private: |
825 | template<typename _Tp1> |
826 | void |
827 | _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept |
828 | { _M_weak_this._M_assign(__p, __n); } |
829 | |
830 | // Found by ADL when this is an associated class. |
831 | friend const enable_shared_from_this* |
832 | __enable_shared_from_this_base(const __shared_count<>&, |
833 | const enable_shared_from_this* __p) |
834 | { return __p; } |
835 | |
836 | template<typename, _Lock_policy> |
837 | friend class __shared_ptr; |
838 | |
839 | mutable weak_ptr<_Tp> _M_weak_this; |
840 | }; |
841 | |
842 | /// @relates shared_ptr @{ |
843 | |
844 | /** |
845 | * @brief Create an object that is owned by a shared_ptr. |
846 | * @param __a An allocator. |
847 | * @param __args Arguments for the @a _Tp object's constructor. |
848 | * @return A shared_ptr that owns the newly created object. |
849 | * @throw An exception thrown from @a _Alloc::allocate or from the |
850 | * constructor of @a _Tp. |
851 | * |
852 | * A copy of @a __a will be used to allocate memory for the shared_ptr |
853 | * and the new object. |
854 | */ |
855 | template<typename _Tp, typename _Alloc, typename... _Args> |
856 | inline shared_ptr<_Tp> |
857 | allocate_shared(const _Alloc& __a, _Args&&... __args) |
858 | { |
859 | return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a}, |
860 | std::forward<_Args>(__args)...); |
861 | } |
862 | |
863 | /** |
864 | * @brief Create an object that is owned by a shared_ptr. |
865 | * @param __args Arguments for the @a _Tp object's constructor. |
866 | * @return A shared_ptr that owns the newly created object. |
867 | * @throw std::bad_alloc, or an exception thrown from the |
868 | * constructor of @a _Tp. |
869 | */ |
870 | template<typename _Tp, typename... _Args> |
871 | inline shared_ptr<_Tp> |
872 | make_shared(_Args&&... __args) |
873 | { |
874 | typedef typename std::remove_cv<_Tp>::type _Tp_nc; |
875 | return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(), |
876 | std::forward<_Args>(__args)...); |
877 | } |
878 | |
879 | /// std::hash specialization for shared_ptr. |
880 | template<typename _Tp> |
881 | struct hash<shared_ptr<_Tp>> |
882 | : public __hash_base<size_t, shared_ptr<_Tp>> |
883 | { |
884 | size_t |
885 | operator()(const shared_ptr<_Tp>& __s) const noexcept |
886 | { |
887 | return std::hash<typename shared_ptr<_Tp>::element_type*>()(__s.get()); |
888 | } |
889 | }; |
890 | |
891 | // @} relates shared_ptr |
892 | // @} group pointer_abstractions |
893 | |
894 | #if __cplusplus201703L >= 201703L |
895 | namespace __detail::__variant |
896 | { |
897 | template<typename> struct _Never_valueless_alt; // see <variant> |
898 | |
899 | // Provide the strong exception-safety guarantee when emplacing a |
900 | // shared_ptr into a variant. |
901 | template<typename _Tp> |
902 | struct _Never_valueless_alt<std::shared_ptr<_Tp>> |
903 | : std::true_type |
904 | { }; |
905 | |
906 | // Provide the strong exception-safety guarantee when emplacing a |
907 | // weak_ptr into a variant. |
908 | template<typename _Tp> |
909 | struct _Never_valueless_alt<std::weak_ptr<_Tp>> |
910 | : std::true_type |
911 | { }; |
912 | } // namespace __detail::__variant |
913 | #endif // C++17 |
914 | |
915 | _GLIBCXX_END_NAMESPACE_VERSION |
916 | } // namespace |
917 | |
918 | #endif // _SHARED_PTR_H |
1 | // shared_ptr and weak_ptr implementation details -*- C++ -*- |
2 | |
3 | // Copyright (C) 2007-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 | // GCC Note: Based on files from version 1.32.0 of the Boost library. |
26 | |
27 | // shared_count.hpp |
28 | // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. |
29 | |
30 | // shared_ptr.hpp |
31 | // Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes. |
32 | // Copyright (C) 2001, 2002, 2003 Peter Dimov |
33 | |
34 | // weak_ptr.hpp |
35 | // Copyright (C) 2001, 2002, 2003 Peter Dimov |
36 | |
37 | // enable_shared_from_this.hpp |
38 | // Copyright (C) 2002 Peter Dimov |
39 | |
40 | // Distributed under the Boost Software License, Version 1.0. (See |
41 | // accompanying file LICENSE_1_0.txt or copy at |
42 | // http://www.boost.org/LICENSE_1_0.txt) |
43 | |
44 | /** @file bits/shared_ptr_base.h |
45 | * This is an internal header file, included by other library headers. |
46 | * Do not attempt to use it directly. @headername{memory} |
47 | */ |
48 | |
49 | #ifndef _SHARED_PTR_BASE_H1 |
50 | #define _SHARED_PTR_BASE_H1 1 |
51 | |
52 | #include <typeinfo> |
53 | #include <bits/allocated_ptr.h> |
54 | #include <bits/refwrap.h> |
55 | #include <bits/stl_function.h> |
56 | #include <ext/aligned_buffer.h> |
57 | #if __cplusplus201703L > 201703L |
58 | # include <compare> |
59 | #endif |
60 | |
61 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
62 | { |
63 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
64 | |
65 | #if _GLIBCXX_USE_DEPRECATED1 |
66 | #pragma GCC diagnostic push |
67 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
68 | template<typename> class auto_ptr; |
69 | #pragma GCC diagnostic pop |
70 | #endif |
71 | |
72 | /** |
73 | * @brief Exception possibly thrown by @c shared_ptr. |
74 | * @ingroup exceptions |
75 | */ |
76 | class bad_weak_ptr : public std::exception |
77 | { |
78 | public: |
79 | virtual char const* what() const noexcept; |
80 | |
81 | virtual ~bad_weak_ptr() noexcept; |
82 | }; |
83 | |
84 | // Substitute for bad_weak_ptr object in the case of -fno-exceptions. |
85 | inline void |
86 | __throw_bad_weak_ptr() |
87 | { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr())(throw (bad_weak_ptr())); } |
88 | |
89 | using __gnu_cxx::_Lock_policy; |
90 | using __gnu_cxx::__default_lock_policy; |
91 | using __gnu_cxx::_S_single; |
92 | using __gnu_cxx::_S_mutex; |
93 | using __gnu_cxx::_S_atomic; |
94 | |
95 | // Empty helper class except when the template argument is _S_mutex. |
96 | template<_Lock_policy _Lp> |
97 | class _Mutex_base |
98 | { |
99 | protected: |
100 | // The atomic policy uses fully-fenced builtins, single doesn't care. |
101 | enum { _S_need_barriers = 0 }; |
102 | }; |
103 | |
104 | template<> |
105 | class _Mutex_base<_S_mutex> |
106 | : public __gnu_cxx::__mutex |
107 | { |
108 | protected: |
109 | // This policy is used when atomic builtins are not available. |
110 | // The replacement atomic operations might not have the necessary |
111 | // memory barriers. |
112 | enum { _S_need_barriers = 1 }; |
113 | }; |
114 | |
115 | template<_Lock_policy _Lp = __default_lock_policy> |
116 | class _Sp_counted_base |
117 | : public _Mutex_base<_Lp> |
118 | { |
119 | public: |
120 | _Sp_counted_base() noexcept |
121 | : _M_use_count(1), _M_weak_count(1) { } |
122 | |
123 | virtual |
124 | ~_Sp_counted_base() noexcept |
125 | { } |
126 | |
127 | // Called when _M_use_count drops to zero, to release the resources |
128 | // managed by *this. |
129 | virtual void |
130 | _M_dispose() noexcept = 0; |
131 | |
132 | // Called when _M_weak_count drops to zero. |
133 | virtual void |
134 | _M_destroy() noexcept |
135 | { delete this; } |
136 | |
137 | virtual void* |
138 | _M_get_deleter(const std::type_info&) noexcept = 0; |
139 | |
140 | void |
141 | _M_add_ref_copy() |
142 | { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); } |
143 | |
144 | void |
145 | _M_add_ref_lock(); |
146 | |
147 | bool |
148 | _M_add_ref_lock_nothrow(); |
149 | |
150 | void |
151 | _M_release() noexcept |
152 | { |
153 | // Be race-detector-friendly. For more info see bits/c++config. |
154 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count); |
155 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) |
156 | { |
157 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count); |
158 | _M_dispose(); |
159 | // There must be a memory barrier between dispose() and destroy() |
160 | // to ensure that the effects of dispose() are observed in the |
161 | // thread that runs destroy(). |
162 | // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html |
163 | if (_Mutex_base<_Lp>::_S_need_barriers) |
164 | { |
165 | __atomic_thread_fence (__ATOMIC_ACQ_REL4); |
166 | } |
167 | |
168 | // Be race-detector-friendly. For more info see bits/c++config. |
169 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); |
170 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, |
171 | -1) == 1) |
172 | { |
173 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); |
174 | _M_destroy(); |
175 | } |
176 | } |
177 | } |
178 | |
179 | void |
180 | _M_weak_add_ref() noexcept |
181 | { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); } |
182 | |
183 | void |
184 | _M_weak_release() noexcept |
185 | { |
186 | // Be race-detector-friendly. For more info see bits/c++config. |
187 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); |
188 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) |
189 | { |
190 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); |
191 | if (_Mutex_base<_Lp>::_S_need_barriers) |
192 | { |
193 | // See _M_release(), |
194 | // destroy() must observe results of dispose() |
195 | __atomic_thread_fence (__ATOMIC_ACQ_REL4); |
196 | } |
197 | _M_destroy(); |
198 | } |
199 | } |
200 | |
201 | long |
202 | _M_get_use_count() const noexcept |
203 | { |
204 | // No memory barrier is used here so there is no synchronization |
205 | // with other threads. |
206 | return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED0); |
207 | } |
208 | |
209 | private: |
210 | _Sp_counted_base(_Sp_counted_base const&) = delete; |
211 | _Sp_counted_base& operator=(_Sp_counted_base const&) = delete; |
212 | |
213 | _Atomic_word _M_use_count; // #shared |
214 | _Atomic_word _M_weak_count; // #weak + (#shared != 0) |
215 | }; |
216 | |
217 | template<> |
218 | inline void |
219 | _Sp_counted_base<_S_single>:: |
220 | _M_add_ref_lock() |
221 | { |
222 | if (_M_use_count == 0) |
223 | __throw_bad_weak_ptr(); |
224 | ++_M_use_count; |
225 | } |
226 | |
227 | template<> |
228 | inline void |
229 | _Sp_counted_base<_S_mutex>:: |
230 | _M_add_ref_lock() |
231 | { |
232 | __gnu_cxx::__scoped_lock sentry(*this); |
233 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) |
234 | { |
235 | _M_use_count = 0; |
236 | __throw_bad_weak_ptr(); |
237 | } |
238 | } |
239 | |
240 | template<> |
241 | inline void |
242 | _Sp_counted_base<_S_atomic>:: |
243 | _M_add_ref_lock() |
244 | { |
245 | // Perform lock-free add-if-not-zero operation. |
246 | _Atomic_word __count = _M_get_use_count(); |
247 | do |
248 | { |
249 | if (__count == 0) |
250 | __throw_bad_weak_ptr(); |
251 | // Replace the current counter value with the old value + 1, as |
252 | // long as it's not changed meanwhile. |
253 | } |
254 | while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, |
255 | true, __ATOMIC_ACQ_REL4, |
256 | __ATOMIC_RELAXED0)); |
257 | } |
258 | |
259 | template<> |
260 | inline bool |
261 | _Sp_counted_base<_S_single>:: |
262 | _M_add_ref_lock_nothrow() |
263 | { |
264 | if (_M_use_count == 0) |
265 | return false; |
266 | ++_M_use_count; |
267 | return true; |
268 | } |
269 | |
270 | template<> |
271 | inline bool |
272 | _Sp_counted_base<_S_mutex>:: |
273 | _M_add_ref_lock_nothrow() |
274 | { |
275 | __gnu_cxx::__scoped_lock sentry(*this); |
276 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) |
277 | { |
278 | _M_use_count = 0; |
279 | return false; |
280 | } |
281 | return true; |
282 | } |
283 | |
284 | template<> |
285 | inline bool |
286 | _Sp_counted_base<_S_atomic>:: |
287 | _M_add_ref_lock_nothrow() |
288 | { |
289 | // Perform lock-free add-if-not-zero operation. |
290 | _Atomic_word __count = _M_get_use_count(); |
291 | do |
292 | { |
293 | if (__count == 0) |
294 | return false; |
295 | // Replace the current counter value with the old value + 1, as |
296 | // long as it's not changed meanwhile. |
297 | } |
298 | while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, |
299 | true, __ATOMIC_ACQ_REL4, |
300 | __ATOMIC_RELAXED0)); |
301 | return true; |
302 | } |
303 | |
304 | template<> |
305 | inline void |
306 | _Sp_counted_base<_S_single>::_M_add_ref_copy() |
307 | { ++_M_use_count; } |
308 | |
309 | template<> |
310 | inline void |
311 | _Sp_counted_base<_S_single>::_M_release() noexcept |
312 | { |
313 | if (--_M_use_count == 0) |
314 | { |
315 | _M_dispose(); |
316 | if (--_M_weak_count == 0) |
317 | _M_destroy(); |
318 | } |
319 | } |
320 | |
321 | template<> |
322 | inline void |
323 | _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept |
324 | { ++_M_weak_count; } |
325 | |
326 | template<> |
327 | inline void |
328 | _Sp_counted_base<_S_single>::_M_weak_release() noexcept |
329 | { |
330 | if (--_M_weak_count == 0) |
331 | _M_destroy(); |
332 | } |
333 | |
334 | template<> |
335 | inline long |
336 | _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept |
337 | { return _M_use_count; } |
338 | |
339 | |
340 | // Forward declarations. |
341 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
342 | class __shared_ptr; |
343 | |
344 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
345 | class __weak_ptr; |
346 | |
347 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
348 | class __enable_shared_from_this; |
349 | |
350 | template<typename _Tp> |
351 | class shared_ptr; |
352 | |
353 | template<typename _Tp> |
354 | class weak_ptr; |
355 | |
356 | template<typename _Tp> |
357 | struct owner_less; |
358 | |
359 | template<typename _Tp> |
360 | class enable_shared_from_this; |
361 | |
362 | template<_Lock_policy _Lp = __default_lock_policy> |
363 | class __weak_count; |
364 | |
365 | template<_Lock_policy _Lp = __default_lock_policy> |
366 | class __shared_count; |
367 | |
368 | |
369 | // Counted ptr with no deleter or allocator support |
370 | template<typename _Ptr, _Lock_policy _Lp> |
371 | class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> |
372 | { |
373 | public: |
374 | explicit |
375 | _Sp_counted_ptr(_Ptr __p) noexcept |
376 | : _M_ptr(__p) { } |
377 | |
378 | virtual void |
379 | _M_dispose() noexcept |
380 | { delete _M_ptr; } |
381 | |
382 | virtual void |
383 | _M_destroy() noexcept |
384 | { delete this; } |
385 | |
386 | virtual void* |
387 | _M_get_deleter(const std::type_info&) noexcept |
388 | { return nullptr; } |
389 | |
390 | _Sp_counted_ptr(const _Sp_counted_ptr&) = delete; |
391 | _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete; |
392 | |
393 | private: |
394 | _Ptr _M_ptr; |
395 | }; |
396 | |
397 | template<> |
398 | inline void |
399 | _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept { } |
400 | |
401 | template<> |
402 | inline void |
403 | _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept { } |
404 | |
405 | template<> |
406 | inline void |
407 | _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { } |
408 | |
409 | template<int _Nm, typename _Tp, |
410 | bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> |
411 | struct _Sp_ebo_helper; |
412 | |
413 | /// Specialization using EBO. |
414 | template<int _Nm, typename _Tp> |
415 | struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp |
416 | { |
417 | explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { } |
418 | explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { } |
419 | |
420 | static _Tp& |
421 | _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); } |
422 | }; |
423 | |
424 | /// Specialization not using EBO. |
425 | template<int _Nm, typename _Tp> |
426 | struct _Sp_ebo_helper<_Nm, _Tp, false> |
427 | { |
428 | explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { } |
429 | explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { } |
430 | |
431 | static _Tp& |
432 | _S_get(_Sp_ebo_helper& __eboh) |
433 | { return __eboh._M_tp; } |
434 | |
435 | private: |
436 | _Tp _M_tp; |
437 | }; |
438 | |
439 | // Support for custom deleter and/or allocator |
440 | template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp> |
441 | class _Sp_counted_deleter final : public _Sp_counted_base<_Lp> |
442 | { |
443 | class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc> |
444 | { |
445 | typedef _Sp_ebo_helper<0, _Deleter> _Del_base; |
446 | typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base; |
447 | |
448 | public: |
449 | _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept |
450 | : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a) |
451 | { } |
452 | |
453 | _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); } |
454 | _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); } |
455 | |
456 | _Ptr _M_ptr; |
457 | }; |
458 | |
459 | public: |
460 | using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>; |
461 | |
462 | // __d(__p) must not throw. |
463 | _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept |
464 | : _M_impl(__p, std::move(__d), _Alloc()) { } |
465 | |
466 | // __d(__p) must not throw. |
467 | _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept |
468 | : _M_impl(__p, std::move(__d), __a) { } |
469 | |
470 | ~_Sp_counted_deleter() noexcept { } |
471 | |
472 | virtual void |
473 | _M_dispose() noexcept |
474 | { _M_impl._M_del()(_M_impl._M_ptr); } |
475 | |
476 | virtual void |
477 | _M_destroy() noexcept |
478 | { |
479 | __allocator_type __a(_M_impl._M_alloc()); |
480 | __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; |
481 | this->~_Sp_counted_deleter(); |
482 | } |
483 | |
484 | virtual void* |
485 | _M_get_deleter(const std::type_info& __ti) noexcept |
486 | { |
487 | #if __cpp_rtti199711L |
488 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
489 | // 2400. shared_ptr's get_deleter() should use addressof() |
490 | return __ti == typeid(_Deleter) |
491 | ? std::__addressof(_M_impl._M_del()) |
492 | : nullptr; |
493 | #else |
494 | return nullptr; |
495 | #endif |
496 | } |
497 | |
498 | private: |
499 | _Impl _M_impl; |
500 | }; |
501 | |
502 | // helpers for make_shared / allocate_shared |
503 | |
504 | struct _Sp_make_shared_tag |
505 | { |
506 | private: |
507 | template<typename _Tp, typename _Alloc, _Lock_policy _Lp> |
508 | friend class _Sp_counted_ptr_inplace; |
509 | |
510 | static const type_info& |
511 | _S_ti() noexcept _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
512 | { |
513 | alignas(type_info) static constexpr char __tag[sizeof(type_info)] = { }; |
514 | return reinterpret_cast<const type_info&>(__tag); |
515 | } |
516 | |
517 | static bool _S_eq(const type_info&) noexcept; |
518 | }; |
519 | |
520 | template<typename _Alloc> |
521 | struct _Sp_alloc_shared_tag |
522 | { |
523 | const _Alloc& _M_a; |
524 | }; |
525 | |
526 | template<typename _Tp, typename _Alloc, _Lock_policy _Lp> |
527 | class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> |
528 | { |
529 | class _Impl : _Sp_ebo_helper<0, _Alloc> |
530 | { |
531 | typedef _Sp_ebo_helper<0, _Alloc> _A_base; |
532 | |
533 | public: |
534 | explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { } |
535 | |
536 | _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); } |
537 | |
538 | __gnu_cxx::__aligned_buffer<_Tp> _M_storage; |
539 | }; |
540 | |
541 | public: |
542 | using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>; |
543 | |
544 | // Alloc parameter is not a reference so doesn't alias anything in __args |
545 | template<typename... _Args> |
546 | _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) |
547 | : _M_impl(__a) |
548 | { |
549 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
550 | // 2070. allocate_shared should use allocator_traits<A>::construct |
551 | allocator_traits<_Alloc>::construct(__a, _M_ptr(), |
552 | std::forward<_Args>(__args)...); // might throw |
553 | } |
554 | |
555 | ~_Sp_counted_ptr_inplace() noexcept { } |
556 | |
557 | virtual void |
558 | _M_dispose() noexcept |
559 | { |
560 | allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr()); |
561 | } |
562 | |
563 | // Override because the allocator needs to know the dynamic type |
564 | virtual void |
565 | _M_destroy() noexcept |
566 | { |
567 | __allocator_type __a(_M_impl._M_alloc()); |
568 | __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; |
569 | this->~_Sp_counted_ptr_inplace(); |
570 | } |
571 | |
572 | private: |
573 | friend class __shared_count<_Lp>; // To be able to call _M_ptr(). |
574 | |
575 | // No longer used, but code compiled against old libstdc++ headers |
576 | // might still call it from __shared_ptr ctor to get the pointer out. |
577 | virtual void* |
578 | _M_get_deleter(const std::type_info& __ti) noexcept override |
579 | { |
580 | auto __ptr = const_cast<typename remove_cv<_Tp>::type*>(_M_ptr()); |
581 | // Check for the fake type_info first, so we don't try to access it |
582 | // as a real type_info object. Otherwise, check if it's the real |
583 | // type_info for this class. With RTTI enabled we can check directly, |
584 | // or call a library function to do it. |
585 | if (&__ti == &_Sp_make_shared_tag::_S_ti() |
586 | || |
587 | #if __cpp_rtti199711L |
588 | __ti == typeid(_Sp_make_shared_tag) |
589 | #else |
590 | _Sp_make_shared_tag::_S_eq(__ti) |
591 | #endif |
592 | ) |
593 | return __ptr; |
594 | return nullptr; |
595 | } |
596 | |
597 | _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); } |
598 | |
599 | _Impl _M_impl; |
600 | }; |
601 | |
602 | // The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>. |
603 | struct __sp_array_delete |
604 | { |
605 | template<typename _Yp> |
606 | void operator()(_Yp* __p) const { delete[] __p; } |
607 | }; |
608 | |
609 | template<_Lock_policy _Lp> |
610 | class __shared_count |
611 | { |
612 | template<typename _Tp> |
613 | struct __not_alloc_shared_tag { using type = void; }; |
614 | |
615 | template<typename _Tp> |
616 | struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { }; |
617 | |
618 | public: |
619 | constexpr __shared_count() noexcept : _M_pi(0) |
620 | { } |
621 | |
622 | template<typename _Ptr> |
623 | explicit |
624 | __shared_count(_Ptr __p) : _M_pi(0) |
625 | { |
626 | __trytry |
627 | { |
628 | _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); |
629 | } |
630 | __catch(...)catch(...) |
631 | { |
632 | delete __p; |
633 | __throw_exception_againthrow; |
634 | } |
635 | } |
636 | |
637 | template<typename _Ptr> |
638 | __shared_count(_Ptr __p, /* is_array = */ false_type) |
639 | : __shared_count(__p) |
640 | { } |
641 | |
642 | template<typename _Ptr> |
643 | __shared_count(_Ptr __p, /* is_array = */ true_type) |
644 | : __shared_count(__p, __sp_array_delete{}, allocator<void>()) |
645 | { } |
646 | |
647 | template<typename _Ptr, typename _Deleter, |
648 | typename = typename __not_alloc_shared_tag<_Deleter>::type> |
649 | __shared_count(_Ptr __p, _Deleter __d) |
650 | : __shared_count(__p, std::move(__d), allocator<void>()) |
651 | { } |
652 | |
653 | template<typename _Ptr, typename _Deleter, typename _Alloc, |
654 | typename = typename __not_alloc_shared_tag<_Deleter>::type> |
655 | __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0) |
656 | { |
657 | typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type; |
658 | __trytry |
659 | { |
660 | typename _Sp_cd_type::__allocator_type __a2(__a); |
661 | auto __guard = std::__allocate_guarded(__a2); |
662 | _Sp_cd_type* __mem = __guard.get(); |
663 | ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a)); |
664 | _M_pi = __mem; |
665 | __guard = nullptr; |
666 | } |
667 | __catch(...)catch(...) |
668 | { |
669 | __d(__p); // Call _Deleter on __p. |
670 | __throw_exception_againthrow; |
671 | } |
672 | } |
673 | |
674 | template<typename _Tp, typename _Alloc, typename... _Args> |
675 | __shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a, |
676 | _Args&&... __args) |
677 | { |
678 | typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type; |
679 | typename _Sp_cp_type::__allocator_type __a2(__a._M_a); |
680 | auto __guard = std::__allocate_guarded(__a2); |
681 | _Sp_cp_type* __mem = __guard.get(); |
682 | auto __pi = ::new (__mem) |
683 | _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...); |
684 | __guard = nullptr; |
685 | _M_pi = __pi; |
686 | __p = __pi->_M_ptr(); |
687 | } |
688 | |
689 | #if _GLIBCXX_USE_DEPRECATED1 |
690 | #pragma GCC diagnostic push |
691 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
692 | // Special case for auto_ptr<_Tp> to provide the strong guarantee. |
693 | template<typename _Tp> |
694 | explicit |
695 | __shared_count(std::auto_ptr<_Tp>&& __r); |
696 | #pragma GCC diagnostic pop |
697 | #endif |
698 | |
699 | // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee. |
700 | template<typename _Tp, typename _Del> |
701 | explicit |
702 | __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0) |
703 | { |
704 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
705 | // 2415. Inconsistency between unique_ptr and shared_ptr |
706 | if (__r.get() == nullptr) |
707 | return; |
708 | |
709 | using _Ptr = typename unique_ptr<_Tp, _Del>::pointer; |
710 | using _Del2 = typename conditional<is_reference<_Del>::value, |
711 | reference_wrapper<typename remove_reference<_Del>::type>, |
712 | _Del>::type; |
713 | using _Sp_cd_type |
714 | = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>; |
715 | using _Alloc = allocator<_Sp_cd_type>; |
716 | using _Alloc_traits = allocator_traits<_Alloc>; |
717 | _Alloc __a; |
718 | _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1); |
719 | _Alloc_traits::construct(__a, __mem, __r.release(), |
720 | __r.get_deleter()); // non-throwing |
721 | _M_pi = __mem; |
722 | } |
723 | |
724 | // Throw bad_weak_ptr when __r._M_get_use_count() == 0. |
725 | explicit __shared_count(const __weak_count<_Lp>& __r); |
726 | |
727 | // Does not throw if __r._M_get_use_count() == 0, caller must check. |
728 | explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t); |
729 | |
730 | ~__shared_count() noexcept |
731 | { |
732 | if (_M_pi != nullptr) |
733 | _M_pi->_M_release(); |
734 | } |
735 | |
736 | __shared_count(const __shared_count& __r) noexcept |
737 | : _M_pi(__r._M_pi) |
738 | { |
739 | if (_M_pi != 0) |
740 | _M_pi->_M_add_ref_copy(); |
741 | } |
742 | |
743 | __shared_count& |
744 | operator=(const __shared_count& __r) noexcept |
745 | { |
746 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
747 | if (__tmp != _M_pi) |
748 | { |
749 | if (__tmp != 0) |
750 | __tmp->_M_add_ref_copy(); |
751 | if (_M_pi != 0) |
752 | _M_pi->_M_release(); |
753 | _M_pi = __tmp; |
754 | } |
755 | return *this; |
756 | } |
757 | |
758 | void |
759 | _M_swap(__shared_count& __r) noexcept |
760 | { |
761 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
762 | __r._M_pi = _M_pi; |
763 | _M_pi = __tmp; |
764 | } |
765 | |
766 | long |
767 | _M_get_use_count() const noexcept |
768 | { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; } |
769 | |
770 | bool |
771 | _M_unique() const noexcept |
772 | { return this->_M_get_use_count() == 1; } |
773 | |
774 | void* |
775 | _M_get_deleter(const std::type_info& __ti) const noexcept |
776 | { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; } |
777 | |
778 | bool |
779 | _M_less(const __shared_count& __rhs) const noexcept |
780 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
781 | |
782 | bool |
783 | _M_less(const __weak_count<_Lp>& __rhs) const noexcept |
784 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
785 | |
786 | // Friend function injected into enclosing namespace and found by ADL |
787 | friend inline bool |
788 | operator==(const __shared_count& __a, const __shared_count& __b) noexcept |
789 | { return __a._M_pi == __b._M_pi; } |
790 | |
791 | private: |
792 | friend class __weak_count<_Lp>; |
793 | |
794 | _Sp_counted_base<_Lp>* _M_pi; |
795 | }; |
796 | |
797 | |
798 | template<_Lock_policy _Lp> |
799 | class __weak_count |
800 | { |
801 | public: |
802 | constexpr __weak_count() noexcept : _M_pi(nullptr) |
803 | { } |
804 | |
805 | __weak_count(const __shared_count<_Lp>& __r) noexcept |
806 | : _M_pi(__r._M_pi) |
807 | { |
808 | if (_M_pi != nullptr) |
809 | _M_pi->_M_weak_add_ref(); |
810 | } |
811 | |
812 | __weak_count(const __weak_count& __r) noexcept |
813 | : _M_pi(__r._M_pi) |
814 | { |
815 | if (_M_pi != nullptr) |
816 | _M_pi->_M_weak_add_ref(); |
817 | } |
818 | |
819 | __weak_count(__weak_count&& __r) noexcept |
820 | : _M_pi(__r._M_pi) |
821 | { __r._M_pi = nullptr; } |
822 | |
823 | ~__weak_count() noexcept |
824 | { |
825 | if (_M_pi != nullptr) |
826 | _M_pi->_M_weak_release(); |
827 | } |
828 | |
829 | __weak_count& |
830 | operator=(const __shared_count<_Lp>& __r) noexcept |
831 | { |
832 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
833 | if (__tmp != nullptr) |
834 | __tmp->_M_weak_add_ref(); |
835 | if (_M_pi != nullptr) |
836 | _M_pi->_M_weak_release(); |
837 | _M_pi = __tmp; |
838 | return *this; |
839 | } |
840 | |
841 | __weak_count& |
842 | operator=(const __weak_count& __r) noexcept |
843 | { |
844 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
845 | if (__tmp != nullptr) |
846 | __tmp->_M_weak_add_ref(); |
847 | if (_M_pi != nullptr) |
848 | _M_pi->_M_weak_release(); |
849 | _M_pi = __tmp; |
850 | return *this; |
851 | } |
852 | |
853 | __weak_count& |
854 | operator=(__weak_count&& __r) noexcept |
855 | { |
856 | if (_M_pi != nullptr) |
857 | _M_pi->_M_weak_release(); |
858 | _M_pi = __r._M_pi; |
859 | __r._M_pi = nullptr; |
860 | return *this; |
861 | } |
862 | |
863 | void |
864 | _M_swap(__weak_count& __r) noexcept |
865 | { |
866 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
867 | __r._M_pi = _M_pi; |
868 | _M_pi = __tmp; |
869 | } |
870 | |
871 | long |
872 | _M_get_use_count() const noexcept |
873 | { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; } |
874 | |
875 | bool |
876 | _M_less(const __weak_count& __rhs) const noexcept |
877 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
878 | |
879 | bool |
880 | _M_less(const __shared_count<_Lp>& __rhs) const noexcept |
881 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
882 | |
883 | // Friend function injected into enclosing namespace and found by ADL |
884 | friend inline bool |
885 | operator==(const __weak_count& __a, const __weak_count& __b) noexcept |
886 | { return __a._M_pi == __b._M_pi; } |
887 | |
888 | private: |
889 | friend class __shared_count<_Lp>; |
890 | |
891 | _Sp_counted_base<_Lp>* _M_pi; |
892 | }; |
893 | |
894 | // Now that __weak_count is defined we can define this constructor: |
895 | template<_Lock_policy _Lp> |
896 | inline |
897 | __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r) |
898 | : _M_pi(__r._M_pi) |
899 | { |
900 | if (_M_pi != nullptr) |
901 | _M_pi->_M_add_ref_lock(); |
902 | else |
903 | __throw_bad_weak_ptr(); |
904 | } |
905 | |
906 | // Now that __weak_count is defined we can define this constructor: |
907 | template<_Lock_policy _Lp> |
908 | inline |
909 | __shared_count<_Lp>:: |
910 | __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) |
911 | : _M_pi(__r._M_pi) |
912 | { |
913 | if (_M_pi != nullptr) |
914 | if (!_M_pi->_M_add_ref_lock_nothrow()) |
915 | _M_pi = nullptr; |
916 | } |
917 | |
918 | #define __cpp_lib_shared_ptr_arrays201611L 201611L |
919 | |
920 | // Helper traits for shared_ptr of array: |
921 | |
922 | // A pointer type Y* is said to be compatible with a pointer type T* when |
923 | // either Y* is convertible to T* or Y is U[N] and T is U cv []. |
924 | template<typename _Yp_ptr, typename _Tp_ptr> |
925 | struct __sp_compatible_with |
926 | : false_type |
927 | { }; |
928 | |
929 | template<typename _Yp, typename _Tp> |
930 | struct __sp_compatible_with<_Yp*, _Tp*> |
931 | : is_convertible<_Yp*, _Tp*>::type |
932 | { }; |
933 | |
934 | template<typename _Up, size_t _Nm> |
935 | struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]> |
936 | : true_type |
937 | { }; |
938 | |
939 | template<typename _Up, size_t _Nm> |
940 | struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]> |
941 | : true_type |
942 | { }; |
943 | |
944 | template<typename _Up, size_t _Nm> |
945 | struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]> |
946 | : true_type |
947 | { }; |
948 | |
949 | template<typename _Up, size_t _Nm> |
950 | struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]> |
951 | : true_type |
952 | { }; |
953 | |
954 | // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N]. |
955 | template<typename _Up, size_t _Nm, typename _Yp, typename = void> |
956 | struct __sp_is_constructible_arrN |
957 | : false_type |
958 | { }; |
959 | |
960 | template<typename _Up, size_t _Nm, typename _Yp> |
961 | struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>> |
962 | : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type |
963 | { }; |
964 | |
965 | // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[]. |
966 | template<typename _Up, typename _Yp, typename = void> |
967 | struct __sp_is_constructible_arr |
968 | : false_type |
969 | { }; |
970 | |
971 | template<typename _Up, typename _Yp> |
972 | struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>> |
973 | : is_convertible<_Yp(*)[], _Up(*)[]>::type |
974 | { }; |
975 | |
976 | // Trait to check if shared_ptr<T> can be constructed from Y*. |
977 | template<typename _Tp, typename _Yp> |
978 | struct __sp_is_constructible; |
979 | |
980 | // When T is U[N], Y(*)[N] shall be convertible to T*; |
981 | template<typename _Up, size_t _Nm, typename _Yp> |
982 | struct __sp_is_constructible<_Up[_Nm], _Yp> |
983 | : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type |
984 | { }; |
985 | |
986 | // when T is U[], Y(*)[] shall be convertible to T*; |
987 | template<typename _Up, typename _Yp> |
988 | struct __sp_is_constructible<_Up[], _Yp> |
989 | : __sp_is_constructible_arr<_Up, _Yp>::type |
990 | { }; |
991 | |
992 | // otherwise, Y* shall be convertible to T*. |
993 | template<typename _Tp, typename _Yp> |
994 | struct __sp_is_constructible |
995 | : is_convertible<_Yp*, _Tp*>::type |
996 | { }; |
997 | |
998 | |
999 | // Define operator* and operator-> for shared_ptr<T>. |
1000 | template<typename _Tp, _Lock_policy _Lp, |
1001 | bool = is_array<_Tp>::value, bool = is_void<_Tp>::value> |
1002 | class __shared_ptr_access |
1003 | { |
1004 | public: |
1005 | using element_type = _Tp; |
1006 | |
1007 | element_type& |
1008 | operator*() const noexcept |
1009 | { |
1010 | __glibcxx_assert(_M_get() != nullptr); |
1011 | return *_M_get(); |
1012 | } |
1013 | |
1014 | element_type* |
1015 | operator->() const noexcept |
1016 | { |
1017 | _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); |
1018 | return _M_get(); |
1019 | } |
1020 | |
1021 | private: |
1022 | element_type* |
1023 | _M_get() const noexcept |
1024 | { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); } |
1025 | }; |
1026 | |
1027 | // Define operator-> for shared_ptr<cv void>. |
1028 | template<typename _Tp, _Lock_policy _Lp> |
1029 | class __shared_ptr_access<_Tp, _Lp, false, true> |
1030 | { |
1031 | public: |
1032 | using element_type = _Tp; |
1033 | |
1034 | element_type* |
1035 | operator->() const noexcept |
1036 | { |
1037 | auto __ptr = static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); |
1038 | _GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr); |
1039 | return __ptr; |
1040 | } |
1041 | }; |
1042 | |
1043 | // Define operator[] for shared_ptr<T[]> and shared_ptr<T[N]>. |
1044 | template<typename _Tp, _Lock_policy _Lp> |
1045 | class __shared_ptr_access<_Tp, _Lp, true, false> |
1046 | { |
1047 | public: |
1048 | using element_type = typename remove_extent<_Tp>::type; |
1049 | |
1050 | #if __cplusplus201703L <= 201402L |
1051 | [[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]] |
1052 | element_type& |
1053 | operator*() const noexcept |
1054 | { |
1055 | __glibcxx_assert(_M_get() != nullptr); |
1056 | return *_M_get(); |
1057 | } |
1058 | |
1059 | [[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]] |
1060 | element_type* |
1061 | operator->() const noexcept |
1062 | { |
1063 | _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); |
1064 | return _M_get(); |
1065 | } |
1066 | #endif |
1067 | |
1068 | element_type& |
1069 | operator[](ptrdiff_t __i) const |
1070 | { |
1071 | __glibcxx_assert(_M_get() != nullptr); |
1072 | __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value); |
1073 | return _M_get()[__i]; |
1074 | } |
1075 | |
1076 | private: |
1077 | element_type* |
1078 | _M_get() const noexcept |
1079 | { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); } |
1080 | }; |
1081 | |
1082 | template<typename _Tp, _Lock_policy _Lp> |
1083 | class __shared_ptr |
1084 | : public __shared_ptr_access<_Tp, _Lp> |
1085 | { |
1086 | public: |
1087 | using element_type = typename remove_extent<_Tp>::type; |
1088 | |
1089 | private: |
1090 | // Constraint for taking ownership of a pointer of type _Yp*: |
1091 | template<typename _Yp> |
1092 | using _SafeConv |
1093 | = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type; |
1094 | |
1095 | // Constraint for construction from shared_ptr and weak_ptr: |
1096 | template<typename _Yp, typename _Res = void> |
1097 | using _Compatible = typename |
1098 | enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; |
1099 | |
1100 | // Constraint for assignment from shared_ptr and weak_ptr: |
1101 | template<typename _Yp> |
1102 | using _Assignable = _Compatible<_Yp, __shared_ptr&>; |
1103 | |
1104 | // Constraint for construction from unique_ptr: |
1105 | template<typename _Yp, typename _Del, typename _Res = void, |
1106 | typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer> |
1107 | using _UniqCompatible = typename enable_if<__and_< |
1108 | __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*> |
1109 | >::value, _Res>::type; |
1110 | |
1111 | // Constraint for assignment from unique_ptr: |
1112 | template<typename _Yp, typename _Del> |
1113 | using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>; |
1114 | |
1115 | public: |
1116 | |
1117 | #if __cplusplus201703L > 201402L |
1118 | using weak_type = __weak_ptr<_Tp, _Lp>; |
1119 | #endif |
1120 | |
1121 | constexpr __shared_ptr() noexcept |
1122 | : _M_ptr(0), _M_refcount() |
1123 | { } |
1124 | |
1125 | template<typename _Yp, typename = _SafeConv<_Yp>> |
1126 | explicit |
1127 | __shared_ptr(_Yp* __p) |
1128 | : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()) |
1129 | { |
1130 | static_assert( !is_void<_Yp>::value, "incomplete type" ); |
1131 | static_assert( sizeof(_Yp) > 0, "incomplete type" ); |
1132 | _M_enable_shared_from_this_with(__p); |
1133 | } |
1134 | |
1135 | template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>> |
1136 | __shared_ptr(_Yp* __p, _Deleter __d) |
1137 | : _M_ptr(__p), _M_refcount(__p, std::move(__d)) |
1138 | { |
1139 | static_assert(__is_invocable<_Deleter&, _Yp*&>::value, |
1140 | "deleter expression d(p) is well-formed"); |
1141 | _M_enable_shared_from_this_with(__p); |
1142 | } |
1143 | |
1144 | template<typename _Yp, typename _Deleter, typename _Alloc, |
1145 | typename = _SafeConv<_Yp>> |
1146 | __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) |
1147 | : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a)) |
1148 | { |
1149 | static_assert(__is_invocable<_Deleter&, _Yp*&>::value, |
1150 | "deleter expression d(p) is well-formed"); |
1151 | _M_enable_shared_from_this_with(__p); |
1152 | } |
1153 | |
1154 | template<typename _Deleter> |
1155 | __shared_ptr(nullptr_t __p, _Deleter __d) |
1156 | : _M_ptr(0), _M_refcount(__p, std::move(__d)) |
1157 | { } |
1158 | |
1159 | template<typename _Deleter, typename _Alloc> |
1160 | __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) |
1161 | : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a)) |
1162 | { } |
1163 | |
1164 | // Aliasing constructor |
1165 | template<typename _Yp> |
1166 | __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r, |
1167 | element_type* __p) noexcept |
1168 | : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws |
1169 | { } |
1170 | |
1171 | // Aliasing constructor |
1172 | template<typename _Yp> |
1173 | __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r, |
1174 | element_type* __p) noexcept |
1175 | : _M_ptr(__p), _M_refcount() |
1176 | { |
1177 | _M_refcount._M_swap(__r._M_refcount); |
1178 | __r._M_ptr = 0; |
1179 | } |
1180 | |
1181 | __shared_ptr(const __shared_ptr&) noexcept = default; |
1182 | __shared_ptr& operator=(const __shared_ptr&) noexcept = default; |
1183 | ~__shared_ptr() = default; |
1184 | |
1185 | template<typename _Yp, typename = _Compatible<_Yp>> |
1186 | __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1187 | : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) |
1188 | { } |
1189 | |
1190 | __shared_ptr(__shared_ptr&& __r) noexcept |
1191 | : _M_ptr(__r._M_ptr), _M_refcount() |
1192 | { |
1193 | _M_refcount._M_swap(__r._M_refcount); |
1194 | __r._M_ptr = 0; |
1195 | } |
1196 | |
1197 | template<typename _Yp, typename = _Compatible<_Yp>> |
1198 | __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept |
1199 | : _M_ptr(__r._M_ptr), _M_refcount() |
1200 | { |
1201 | _M_refcount._M_swap(__r._M_refcount); |
1202 | __r._M_ptr = 0; |
1203 | } |
1204 | |
1205 | template<typename _Yp, typename = _Compatible<_Yp>> |
1206 | explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r) |
1207 | : _M_refcount(__r._M_refcount) // may throw |
1208 | { |
1209 | // It is now safe to copy __r._M_ptr, as |
1210 | // _M_refcount(__r._M_refcount) did not throw. |
1211 | _M_ptr = __r._M_ptr; |
1212 | } |
1213 | |
1214 | // If an exception is thrown this constructor has no effect. |
1215 | template<typename _Yp, typename _Del, |
1216 | typename = _UniqCompatible<_Yp, _Del>> |
1217 | __shared_ptr(unique_ptr<_Yp, _Del>&& __r) |
1218 | : _M_ptr(__r.get()), _M_refcount() |
1219 | { |
1220 | auto __raw = __to_address(__r.get()); |
1221 | _M_refcount = __shared_count<_Lp>(std::move(__r)); |
1222 | _M_enable_shared_from_this_with(__raw); |
1223 | } |
1224 | |
1225 | #if __cplusplus201703L <= 201402L && _GLIBCXX_USE_DEPRECATED1 |
1226 | protected: |
1227 | // If an exception is thrown this constructor has no effect. |
1228 | template<typename _Tp1, typename _Del, |
1229 | typename enable_if<__and_< |
1230 | __not_<is_array<_Tp>>, is_array<_Tp1>, |
1231 | is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*> |
1232 | >::value, bool>::type = true> |
1233 | __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete) |
1234 | : _M_ptr(__r.get()), _M_refcount() |
1235 | { |
1236 | auto __raw = __to_address(__r.get()); |
1237 | _M_refcount = __shared_count<_Lp>(std::move(__r)); |
1238 | _M_enable_shared_from_this_with(__raw); |
1239 | } |
1240 | public: |
1241 | #endif |
1242 | |
1243 | #if _GLIBCXX_USE_DEPRECATED1 |
1244 | #pragma GCC diagnostic push |
1245 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
1246 | // Postcondition: use_count() == 1 and __r.get() == 0 |
1247 | template<typename _Yp, typename = _Compatible<_Yp>> |
1248 | __shared_ptr(auto_ptr<_Yp>&& __r); |
1249 | #pragma GCC diagnostic pop |
1250 | #endif |
1251 | |
1252 | constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } |
1253 | |
1254 | template<typename _Yp> |
1255 | _Assignable<_Yp> |
1256 | operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1257 | { |
1258 | _M_ptr = __r._M_ptr; |
1259 | _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw |
1260 | return *this; |
1261 | } |
1262 | |
1263 | #if _GLIBCXX_USE_DEPRECATED1 |
1264 | #pragma GCC diagnostic push |
1265 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
1266 | template<typename _Yp> |
1267 | _Assignable<_Yp> |
1268 | operator=(auto_ptr<_Yp>&& __r) |
1269 | { |
1270 | __shared_ptr(std::move(__r)).swap(*this); |
1271 | return *this; |
1272 | } |
1273 | #pragma GCC diagnostic pop |
1274 | #endif |
1275 | |
1276 | __shared_ptr& |
1277 | operator=(__shared_ptr&& __r) noexcept |
1278 | { |
1279 | __shared_ptr(std::move(__r)).swap(*this); |
1280 | return *this; |
1281 | } |
1282 | |
1283 | template<class _Yp> |
1284 | _Assignable<_Yp> |
1285 | operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept |
1286 | { |
1287 | __shared_ptr(std::move(__r)).swap(*this); |
1288 | return *this; |
1289 | } |
1290 | |
1291 | template<typename _Yp, typename _Del> |
1292 | _UniqAssignable<_Yp, _Del> |
1293 | operator=(unique_ptr<_Yp, _Del>&& __r) |
1294 | { |
1295 | __shared_ptr(std::move(__r)).swap(*this); |
1296 | return *this; |
1297 | } |
1298 | |
1299 | void |
1300 | reset() noexcept |
1301 | { __shared_ptr().swap(*this); } |
1302 | |
1303 | template<typename _Yp> |
1304 | _SafeConv<_Yp> |
1305 | reset(_Yp* __p) // _Yp must be complete. |
1306 | { |
1307 | // Catch self-reset errors. |
1308 | __glibcxx_assert(__p == 0 || __p != _M_ptr); |
1309 | __shared_ptr(__p).swap(*this); |
1310 | } |
1311 | |
1312 | template<typename _Yp, typename _Deleter> |
1313 | _SafeConv<_Yp> |
1314 | reset(_Yp* __p, _Deleter __d) |
1315 | { __shared_ptr(__p, std::move(__d)).swap(*this); } |
1316 | |
1317 | template<typename _Yp, typename _Deleter, typename _Alloc> |
1318 | _SafeConv<_Yp> |
1319 | reset(_Yp* __p, _Deleter __d, _Alloc __a) |
1320 | { __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); } |
1321 | |
1322 | /// Return the stored pointer. |
1323 | element_type* |
1324 | get() const noexcept |
1325 | { return _M_ptr; } |
1326 | |
1327 | /// Return true if the stored pointer is not null. |
1328 | explicit operator bool() const // never throws |
1329 | { return _M_ptr == 0 ? false : true; } |
1330 | |
1331 | /// Return true if use_count() == 1. |
1332 | bool |
1333 | unique() const noexcept |
1334 | { return _M_refcount._M_unique(); } |
1335 | |
1336 | /// If *this owns a pointer, return the number of owners, otherwise zero. |
1337 | long |
1338 | use_count() const noexcept |
1339 | { return _M_refcount._M_get_use_count(); } |
1340 | |
1341 | /// Exchange both the owned pointer and the stored pointer. |
1342 | void |
1343 | swap(__shared_ptr<_Tp, _Lp>& __other) noexcept |
1344 | { |
1345 | std::swap(_M_ptr, __other._M_ptr); |
1346 | _M_refcount._M_swap(__other._M_refcount); |
1347 | } |
1348 | |
1349 | /** @brief Define an ordering based on ownership. |
1350 | * |
1351 | * This function defines a strict weak ordering between two shared_ptr |
1352 | * or weak_ptr objects, such that one object is less than the other |
1353 | * unless they share ownership of the same pointer, or are both empty. |
1354 | * @{ |
1355 | */ |
1356 | template<typename _Tp1> |
1357 | bool |
1358 | owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept |
1359 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1360 | |
1361 | template<typename _Tp1> |
1362 | bool |
1363 | owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept |
1364 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1365 | // @} |
1366 | |
1367 | protected: |
1368 | // This constructor is non-standard, it is used by allocate_shared. |
1369 | template<typename _Alloc, typename... _Args> |
1370 | __shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args) |
1371 | : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...) |
1372 | { _M_enable_shared_from_this_with(_M_ptr); } |
1373 | |
1374 | template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc, |
1375 | typename... _Args> |
1376 | friend __shared_ptr<_Tp1, _Lp1> |
1377 | __allocate_shared(const _Alloc& __a, _Args&&... __args); |
1378 | |
1379 | // This constructor is used by __weak_ptr::lock() and |
1380 | // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t). |
1381 | __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) |
1382 | : _M_refcount(__r._M_refcount, std::nothrow) |
1383 | { |
1384 | _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr; |
1385 | } |
1386 | |
1387 | friend class __weak_ptr<_Tp, _Lp>; |
1388 | |
1389 | private: |
1390 | |
1391 | template<typename _Yp> |
1392 | using __esft_base_t = decltype(__enable_shared_from_this_base( |
1393 | std::declval<const __shared_count<_Lp>&>(), |
1394 | std::declval<_Yp*>())); |
1395 | |
1396 | // Detect an accessible and unambiguous enable_shared_from_this base. |
1397 | template<typename _Yp, typename = void> |
1398 | struct __has_esft_base |
1399 | : false_type { }; |
1400 | |
1401 | template<typename _Yp> |
1402 | struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>> |
1403 | : __not_<is_array<_Tp>> { }; // No enable shared_from_this for arrays |
1404 | |
1405 | template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type> |
1406 | typename enable_if<__has_esft_base<_Yp2>::value>::type |
1407 | _M_enable_shared_from_this_with(_Yp* __p) noexcept |
1408 | { |
1409 | if (auto __base = __enable_shared_from_this_base(_M_refcount, __p)) |
1410 | __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount); |
1411 | } |
1412 | |
1413 | template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type> |
1414 | typename enable_if<!__has_esft_base<_Yp2>::value>::type |
1415 | _M_enable_shared_from_this_with(_Yp*) noexcept |
1416 | { } |
1417 | |
1418 | void* |
1419 | _M_get_deleter(const std::type_info& __ti) const noexcept |
1420 | { return _M_refcount._M_get_deleter(__ti); } |
1421 | |
1422 | template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr; |
1423 | template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr; |
1424 | |
1425 | template<typename _Del, typename _Tp1, _Lock_policy _Lp1> |
1426 | friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; |
1427 | |
1428 | template<typename _Del, typename _Tp1> |
1429 | friend _Del* get_deleter(const shared_ptr<_Tp1>&) noexcept; |
1430 | |
1431 | element_type* _M_ptr; // Contained pointer. |
1432 | __shared_count<_Lp> _M_refcount; // Reference counter. |
1433 | }; |
1434 | |
1435 | |
1436 | // 20.7.2.2.7 shared_ptr comparisons |
1437 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1438 | inline bool |
1439 | operator==(const __shared_ptr<_Tp1, _Lp>& __a, |
1440 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1441 | { return __a.get() == __b.get(); } |
1442 | |
1443 | template<typename _Tp, _Lock_policy _Lp> |
1444 | inline bool |
1445 | operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1446 | { return !__a; } |
1447 | |
1448 | #ifdef __cpp_lib_three_way_comparison |
1449 | template<typename _Tp, typename _Up, _Lock_policy _Lp> |
1450 | inline strong_ordering |
1451 | operator<=>(const __shared_ptr<_Tp, _Lp>& __a, |
1452 | const __shared_ptr<_Up, _Lp>& __b) noexcept |
1453 | { return compare_three_way()(__a.get(), __b.get()); } |
1454 | |
1455 | template<typename _Tp, _Lock_policy _Lp> |
1456 | inline strong_ordering |
1457 | operator<=>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1458 | { |
1459 | using pointer = typename __shared_ptr<_Tp, _Lp>::element_type*; |
1460 | return compare_three_way()(__a.get(), static_cast<pointer>(nullptr)); |
1461 | } |
1462 | #else |
1463 | template<typename _Tp, _Lock_policy _Lp> |
1464 | inline bool |
1465 | operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1466 | { return !__a; } |
1467 | |
1468 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1469 | inline bool |
1470 | operator!=(const __shared_ptr<_Tp1, _Lp>& __a, |
1471 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1472 | { return __a.get() != __b.get(); } |
1473 | |
1474 | template<typename _Tp, _Lock_policy _Lp> |
1475 | inline bool |
1476 | operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1477 | { return (bool)__a; } |
1478 | |
1479 | template<typename _Tp, _Lock_policy _Lp> |
1480 | inline bool |
1481 | operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1482 | { return (bool)__a; } |
1483 | |
1484 | template<typename _Tp, typename _Up, _Lock_policy _Lp> |
1485 | inline bool |
1486 | operator<(const __shared_ptr<_Tp, _Lp>& __a, |
1487 | const __shared_ptr<_Up, _Lp>& __b) noexcept |
1488 | { |
1489 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1490 | using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type; |
1491 | using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; |
1492 | return less<_Vp>()(__a.get(), __b.get()); |
1493 | } |
1494 | |
1495 | template<typename _Tp, _Lock_policy _Lp> |
1496 | inline bool |
1497 | operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1498 | { |
1499 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1500 | return less<_Tp_elt*>()(__a.get(), nullptr); |
1501 | } |
1502 | |
1503 | template<typename _Tp, _Lock_policy _Lp> |
1504 | inline bool |
1505 | operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1506 | { |
1507 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1508 | return less<_Tp_elt*>()(nullptr, __a.get()); |
1509 | } |
1510 | |
1511 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1512 | inline bool |
1513 | operator<=(const __shared_ptr<_Tp1, _Lp>& __a, |
1514 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1515 | { return !(__b < __a); } |
1516 | |
1517 | template<typename _Tp, _Lock_policy _Lp> |
1518 | inline bool |
1519 | operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1520 | { return !(nullptr < __a); } |
1521 | |
1522 | template<typename _Tp, _Lock_policy _Lp> |
1523 | inline bool |
1524 | operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1525 | { return !(__a < nullptr); } |
1526 | |
1527 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1528 | inline bool |
1529 | operator>(const __shared_ptr<_Tp1, _Lp>& __a, |
1530 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1531 | { return (__b < __a); } |
1532 | |
1533 | template<typename _Tp, _Lock_policy _Lp> |
1534 | inline bool |
1535 | operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1536 | { return nullptr < __a; } |
1537 | |
1538 | template<typename _Tp, _Lock_policy _Lp> |
1539 | inline bool |
1540 | operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1541 | { return __a < nullptr; } |
1542 | |
1543 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1544 | inline bool |
1545 | operator>=(const __shared_ptr<_Tp1, _Lp>& __a, |
1546 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1547 | { return !(__a < __b); } |
1548 | |
1549 | template<typename _Tp, _Lock_policy _Lp> |
1550 | inline bool |
1551 | operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1552 | { return !(__a < nullptr); } |
1553 | |
1554 | template<typename _Tp, _Lock_policy _Lp> |
1555 | inline bool |
1556 | operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1557 | { return !(nullptr < __a); } |
1558 | #endif // three-way comparison |
1559 | |
1560 | // 20.7.2.2.8 shared_ptr specialized algorithms. |
1561 | template<typename _Tp, _Lock_policy _Lp> |
1562 | inline void |
1563 | swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept |
1564 | { __a.swap(__b); } |
1565 | |
1566 | // 20.7.2.2.9 shared_ptr casts |
1567 | |
1568 | // The seemingly equivalent code: |
1569 | // shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get())) |
1570 | // will eventually result in undefined behaviour, attempting to |
1571 | // delete the same object twice. |
1572 | /// static_pointer_cast |
1573 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1574 | inline __shared_ptr<_Tp, _Lp> |
1575 | static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1576 | { |
1577 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1578 | return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get())); |
1579 | } |
1580 | |
1581 | // The seemingly equivalent code: |
1582 | // shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get())) |
1583 | // will eventually result in undefined behaviour, attempting to |
1584 | // delete the same object twice. |
1585 | /// const_pointer_cast |
1586 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1587 | inline __shared_ptr<_Tp, _Lp> |
1588 | const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1589 | { |
1590 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1591 | return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get())); |
1592 | } |
1593 | |
1594 | // The seemingly equivalent code: |
1595 | // shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get())) |
1596 | // will eventually result in undefined behaviour, attempting to |
1597 | // delete the same object twice. |
1598 | /// dynamic_pointer_cast |
1599 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1600 | inline __shared_ptr<_Tp, _Lp> |
1601 | dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1602 | { |
1603 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1604 | if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) |
1605 | return _Sp(__r, __p); |
1606 | return _Sp(); |
1607 | } |
1608 | |
1609 | #if __cplusplus201703L > 201402L |
1610 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1611 | inline __shared_ptr<_Tp, _Lp> |
1612 | reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1613 | { |
1614 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1615 | return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); |
1616 | } |
1617 | #endif |
1618 | |
1619 | template<typename _Tp, _Lock_policy _Lp> |
1620 | class __weak_ptr |
1621 | { |
1622 | template<typename _Yp, typename _Res = void> |
1623 | using _Compatible = typename |
1624 | enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; |
1625 | |
1626 | // Constraint for assignment from shared_ptr and weak_ptr: |
1627 | template<typename _Yp> |
1628 | using _Assignable = _Compatible<_Yp, __weak_ptr&>; |
1629 | |
1630 | public: |
1631 | using element_type = typename remove_extent<_Tp>::type; |
1632 | |
1633 | constexpr __weak_ptr() noexcept |
1634 | : _M_ptr(nullptr), _M_refcount() |
1635 | { } |
1636 | |
1637 | __weak_ptr(const __weak_ptr&) noexcept = default; |
1638 | |
1639 | ~__weak_ptr() = default; |
1640 | |
1641 | // The "obvious" converting constructor implementation: |
1642 | // |
1643 | // template<typename _Tp1> |
1644 | // __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r) |
1645 | // : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws |
1646 | // { } |
1647 | // |
1648 | // has a serious problem. |
1649 | // |
1650 | // __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr) |
1651 | // conversion may require access to *__r._M_ptr (virtual inheritance). |
1652 | // |
1653 | // It is not possible to avoid spurious access violations since |
1654 | // in multithreaded programs __r._M_ptr may be invalidated at any point. |
1655 | template<typename _Yp, typename = _Compatible<_Yp>> |
1656 | __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept |
1657 | : _M_refcount(__r._M_refcount) |
1658 | { _M_ptr = __r.lock().get(); } |
1659 | |
1660 | template<typename _Yp, typename = _Compatible<_Yp>> |
1661 | __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1662 | : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) |
1663 | { } |
1664 | |
1665 | __weak_ptr(__weak_ptr&& __r) noexcept |
1666 | : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount)) |
1667 | { __r._M_ptr = nullptr; } |
1668 | |
1669 | template<typename _Yp, typename = _Compatible<_Yp>> |
1670 | __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept |
1671 | : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount)) |
1672 | { __r._M_ptr = nullptr; } |
1673 | |
1674 | __weak_ptr& |
1675 | operator=(const __weak_ptr& __r) noexcept = default; |
1676 | |
1677 | template<typename _Yp> |
1678 | _Assignable<_Yp> |
1679 | operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept |
1680 | { |
1681 | _M_ptr = __r.lock().get(); |
1682 | _M_refcount = __r._M_refcount; |
1683 | return *this; |
1684 | } |
1685 | |
1686 | template<typename _Yp> |
1687 | _Assignable<_Yp> |
1688 | operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1689 | { |
1690 | _M_ptr = __r._M_ptr; |
1691 | _M_refcount = __r._M_refcount; |
1692 | return *this; |
1693 | } |
1694 | |
1695 | __weak_ptr& |
1696 | operator=(__weak_ptr&& __r) noexcept |
1697 | { |
1698 | _M_ptr = __r._M_ptr; |
1699 | _M_refcount = std::move(__r._M_refcount); |
1700 | __r._M_ptr = nullptr; |
1701 | return *this; |
1702 | } |
1703 | |
1704 | template<typename _Yp> |
1705 | _Assignable<_Yp> |
1706 | operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept |
1707 | { |
1708 | _M_ptr = __r.lock().get(); |
1709 | _M_refcount = std::move(__r._M_refcount); |
1710 | __r._M_ptr = nullptr; |
1711 | return *this; |
1712 | } |
1713 | |
1714 | __shared_ptr<_Tp, _Lp> |
1715 | lock() const noexcept |
1716 | { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); } |
1717 | |
1718 | long |
1719 | use_count() const noexcept |
1720 | { return _M_refcount._M_get_use_count(); } |
1721 | |
1722 | bool |
1723 | expired() const noexcept |
1724 | { return _M_refcount._M_get_use_count() == 0; } |
1725 | |
1726 | template<typename _Tp1> |
1727 | bool |
1728 | owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept |
1729 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1730 | |
1731 | template<typename _Tp1> |
1732 | bool |
1733 | owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept |
1734 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1735 | |
1736 | void |
1737 | reset() noexcept |
1738 | { __weak_ptr().swap(*this); } |
1739 | |
1740 | void |
1741 | swap(__weak_ptr& __s) noexcept |
1742 | { |
1743 | std::swap(_M_ptr, __s._M_ptr); |
1744 | _M_refcount._M_swap(__s._M_refcount); |
1745 | } |
1746 | |
1747 | private: |
1748 | // Used by __enable_shared_from_this. |
1749 | void |
1750 | _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept |
1751 | { |
1752 | if (use_count() == 0) |
1753 | { |
1754 | _M_ptr = __ptr; |
1755 | _M_refcount = __refcount; |
1756 | } |
1757 | } |
1758 | |
1759 | template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr; |
1760 | template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr; |
1761 | friend class __enable_shared_from_this<_Tp, _Lp>; |
1762 | friend class enable_shared_from_this<_Tp>; |
1763 | |
1764 | element_type* _M_ptr; // Contained pointer. |
1765 | __weak_count<_Lp> _M_refcount; // Reference counter. |
1766 | }; |
1767 | |
1768 | // 20.7.2.3.6 weak_ptr specialized algorithms. |
1769 | template<typename _Tp, _Lock_policy _Lp> |
1770 | inline void |
1771 | swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept |
1772 | { __a.swap(__b); } |
1773 | |
1774 | template<typename _Tp, typename _Tp1> |
1775 | struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool> |
1776 | { |
1777 | bool |
1778 | operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept |
1779 | { return __lhs.owner_before(__rhs); } |
1780 | |
1781 | bool |
1782 | operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept |
1783 | { return __lhs.owner_before(__rhs); } |
1784 | |
1785 | bool |
1786 | operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept |
1787 | { return __lhs.owner_before(__rhs); } |
1788 | }; |
1789 | |
1790 | template<> |
1791 | struct _Sp_owner_less<void, void> |
1792 | { |
1793 | template<typename _Tp, typename _Up> |
1794 | auto |
1795 | operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept |
1796 | -> decltype(__lhs.owner_before(__rhs)) |
1797 | { return __lhs.owner_before(__rhs); } |
1798 | |
1799 | using is_transparent = void; |
1800 | }; |
1801 | |
1802 | template<typename _Tp, _Lock_policy _Lp> |
1803 | struct owner_less<__shared_ptr<_Tp, _Lp>> |
1804 | : public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>> |
1805 | { }; |
1806 | |
1807 | template<typename _Tp, _Lock_policy _Lp> |
1808 | struct owner_less<__weak_ptr<_Tp, _Lp>> |
1809 | : public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>> |
1810 | { }; |
1811 | |
1812 | |
1813 | template<typename _Tp, _Lock_policy _Lp> |
1814 | class __enable_shared_from_this |
1815 | { |
1816 | protected: |
1817 | constexpr __enable_shared_from_this() noexcept { } |
1818 | |
1819 | __enable_shared_from_this(const __enable_shared_from_this&) noexcept { } |
1820 | |
1821 | __enable_shared_from_this& |
1822 | operator=(const __enable_shared_from_this&) noexcept |
1823 | { return *this; } |
1824 | |
1825 | ~__enable_shared_from_this() { } |
1826 | |
1827 | public: |
1828 | __shared_ptr<_Tp, _Lp> |
1829 | shared_from_this() |
1830 | { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); } |
1831 | |
1832 | __shared_ptr<const _Tp, _Lp> |
1833 | shared_from_this() const |
1834 | { return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); } |
1835 | |
1836 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
1837 | __weak_ptr<_Tp, _Lp> |
1838 | weak_from_this() noexcept |
1839 | { return this->_M_weak_this; } |
1840 | |
1841 | __weak_ptr<const _Tp, _Lp> |
1842 | weak_from_this() const noexcept |
1843 | { return this->_M_weak_this; } |
1844 | #endif |
1845 | |
1846 | private: |
1847 | template<typename _Tp1> |
1848 | void |
1849 | _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept |
1850 | { _M_weak_this._M_assign(__p, __n); } |
1851 | |
1852 | friend const __enable_shared_from_this* |
1853 | __enable_shared_from_this_base(const __shared_count<_Lp>&, |
1854 | const __enable_shared_from_this* __p) |
1855 | { return __p; } |
1856 | |
1857 | template<typename, _Lock_policy> |
1858 | friend class __shared_ptr; |
1859 | |
1860 | mutable __weak_ptr<_Tp, _Lp> _M_weak_this; |
1861 | }; |
1862 | |
1863 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy, |
1864 | typename _Alloc, typename... _Args> |
1865 | inline __shared_ptr<_Tp, _Lp> |
1866 | __allocate_shared(const _Alloc& __a, _Args&&... __args) |
1867 | { |
1868 | return __shared_ptr<_Tp, _Lp>(_Sp_alloc_shared_tag<_Alloc>{__a}, |
1869 | std::forward<_Args>(__args)...); |
1870 | } |
1871 | |
1872 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy, |
1873 | typename... _Args> |
1874 | inline __shared_ptr<_Tp, _Lp> |
1875 | __make_shared(_Args&&... __args) |
1876 | { |
1877 | typedef typename std::remove_const<_Tp>::type _Tp_nc; |
1878 | return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(), |
1879 | std::forward<_Args>(__args)...); |
1880 | } |
1881 | |
1882 | /// std::hash specialization for __shared_ptr. |
1883 | template<typename _Tp, _Lock_policy _Lp> |
1884 | struct hash<__shared_ptr<_Tp, _Lp>> |
1885 | : public __hash_base<size_t, __shared_ptr<_Tp, _Lp>> |
1886 | { |
1887 | size_t |
1888 | operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept |
1889 | { |
1890 | return hash<typename __shared_ptr<_Tp, _Lp>::element_type*>()( |
1891 | __s.get()); |
1892 | } |
1893 | }; |
1894 | |
1895 | _GLIBCXX_END_NAMESPACE_VERSION |
1896 | } // namespace |
1897 | |
1898 | #endif // _SHARED_PTR_BASE_H |