File: | home/maarten/src/libreoffice/core/sw/source/core/doc/CntntIdxStore.cxx |
Warning: | line 99, column 13 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <bookmrk.hxx> | |||
21 | #include <cntfrm.hxx> | |||
22 | #include <doc.hxx> | |||
23 | #include <IDocumentRedlineAccess.hxx> | |||
24 | #include <IDocumentLayoutAccess.hxx> | |||
25 | #include <docary.hxx> | |||
26 | #include <editsh.hxx> | |||
27 | #include <fmtanchr.hxx> | |||
28 | #include <frmfmt.hxx> | |||
29 | #include <functional> | |||
30 | #include <mvsave.hxx> | |||
31 | #include <node.hxx> | |||
32 | #include <pam.hxx> | |||
33 | #include <redline.hxx> | |||
34 | #include <sal/types.h> | |||
35 | #include <unocrsr.hxx> | |||
36 | #include <txtfrm.hxx> | |||
37 | #include <frameformats.hxx> | |||
38 | #include <memory> | |||
39 | ||||
40 | using namespace ::boost; | |||
41 | using namespace ::sw::mark; | |||
42 | ||||
43 | namespace | |||
44 | { | |||
45 | // #i59534: If a paragraph will be split we have to restore some redline positions | |||
46 | // This help function checks a position compared with a node and a content index | |||
47 | ||||
48 | const int BEFORE_NODE = 0; // Position before the given node index | |||
49 | const int BEFORE_SAME_NODE = 1; // Same node index but content index before given content index | |||
50 | const int SAME_POSITION = 2; // Same node index and samecontent index | |||
51 | const int BEHIND_SAME_NODE = 3; // Same node index but content index behind given content index | |||
52 | const int BEHIND_NODE = 4; // Position behind the given node index | |||
53 | ||||
54 | int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, sal_Int32 nContent ) | |||
55 | { | |||
56 | sal_uLong nIndex = rPos.nNode.GetIndex(); | |||
57 | int nReturn = BEFORE_NODE; | |||
58 | if( nIndex == nNode ) | |||
59 | { | |||
60 | const sal_Int32 nCntIdx = rPos.nContent.GetIndex(); | |||
61 | if( nCntIdx < nContent ) | |||
62 | nReturn = BEFORE_SAME_NODE; | |||
63 | else if( nCntIdx == nContent ) | |||
64 | nReturn = SAME_POSITION; | |||
65 | else | |||
66 | nReturn = BEHIND_SAME_NODE; | |||
67 | } | |||
68 | else if( nIndex > nNode ) | |||
69 | nReturn = BEHIND_NODE; | |||
70 | return nReturn; | |||
71 | } | |||
72 | struct MarkEntry | |||
73 | { | |||
74 | long int m_nIdx; | |||
75 | bool m_bOther; | |||
76 | sal_Int32 m_nContent; | |||
77 | #if 0 | |||
78 | #include <sal/log.hxx> | |||
79 | void Dump() | |||
80 | { | |||
81 | SAL_INFO("sw.core", "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/CntntIdxStore.cxx" ":" "81" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/CntntIdxStore.cxx" ":" "81" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core") , ("/home/maarten/src/libreoffice/core/sw/source/core/doc/CntntIdxStore.cxx" ":" "81" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/CntntIdxStore.cxx" ":" "81" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
82 | } | |||
83 | #endif | |||
84 | }; | |||
85 | struct PaMEntry | |||
86 | { | |||
87 | SwPaM* m_pPaM; | |||
88 | bool m_isMark; | |||
89 | sal_Int32 m_nContent; | |||
90 | }; | |||
91 | struct OffsetUpdater | |||
92 | { | |||
93 | const SwContentNode* m_pNewContentNode; | |||
94 | const sal_Int32 m_nOffset; | |||
95 | OffsetUpdater(SwContentNode const * pNewContentNode, sal_Int32 nOffset) | |||
96 | : m_pNewContentNode(pNewContentNode), m_nOffset(nOffset) {}; | |||
97 | void operator()(SwPosition& rPos, sal_Int32 nContent) const | |||
98 | { | |||
99 | rPos.nNode = *m_pNewContentNode; | |||
| ||||
100 | rPos.nContent.Assign(const_cast<SwContentNode*>(m_pNewContentNode), nContent + m_nOffset); | |||
101 | }; | |||
102 | }; | |||
103 | struct LimitUpdater | |||
104 | { | |||
105 | const SwContentNode* m_pNewContentNode; | |||
106 | const sal_uLong m_nLen; | |||
107 | const sal_Int32 m_nCorrLen; | |||
108 | LimitUpdater(SwContentNode const * pNewContentNode, sal_uLong nLen, sal_Int32 nCorrLen) | |||
109 | : m_pNewContentNode(pNewContentNode), m_nLen(nLen), m_nCorrLen(nCorrLen) {}; | |||
110 | void operator()(SwPosition& rPos, sal_Int32 nContent) const | |||
111 | { | |||
112 | rPos.nNode = *m_pNewContentNode; | |||
113 | if( nContent < m_nCorrLen ) | |||
114 | { | |||
115 | rPos.nContent.Assign(const_cast<SwContentNode*>(m_pNewContentNode), std::min( nContent, static_cast<sal_Int32>(m_nLen) ) ); | |||
116 | } | |||
117 | else | |||
118 | { | |||
119 | rPos.nContent -= m_nCorrLen; | |||
120 | } | |||
121 | }; | |||
122 | }; | |||
123 | struct ContentIdxStoreImpl : sw::mark::ContentIdxStore | |||
124 | { | |||
125 | std::vector<MarkEntry> m_aBkmkEntries; | |||
126 | std::vector<MarkEntry> m_aRedlineEntries; | |||
127 | std::vector<MarkEntry> m_aFlyEntries; | |||
128 | std::vector<PaMEntry> m_aUnoCursorEntries; | |||
129 | std::vector<PaMEntry> m_aShellCursorEntries; | |||
130 | typedef std::function<void (SwPosition& rPos, sal_Int32 nContent)> updater_t; | |||
131 | virtual void Clear() override | |||
132 | { | |||
133 | m_aBkmkEntries.clear(); | |||
134 | m_aRedlineEntries.clear(); | |||
135 | m_aFlyEntries.clear(); | |||
136 | m_aUnoCursorEntries.clear(); | |||
137 | m_aShellCursorEntries.clear(); | |||
138 | } | |||
139 | virtual bool Empty() override | |||
140 | { | |||
141 | return m_aBkmkEntries.empty() && m_aRedlineEntries.empty() && m_aFlyEntries.empty() && m_aUnoCursorEntries.empty() && m_aShellCursorEntries.empty(); | |||
142 | } | |||
143 | virtual void Save(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit=false) override | |||
144 | { | |||
145 | SaveBkmks(rDoc, nNode, nContent); | |||
146 | SaveRedlines(rDoc, nNode, nContent); | |||
147 | SaveFlys(rDoc, nNode, nContent, bSaveFlySplit); | |||
148 | SaveUnoCursors(rDoc, nNode, nContent); | |||
149 | SaveShellCursors(rDoc, nNode, nContent); | |||
150 | } | |||
151 | virtual void Restore(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false, RestoreMode eMode = RestoreMode::All) override | |||
152 | { | |||
153 | SwContentNode* pCNd = rDoc.GetNodes()[ nNode ]->GetContentNode(); | |||
154 | updater_t aUpdater = OffsetUpdater(pCNd, nOffset); | |||
| ||||
155 | if (eMode & RestoreMode::NonFlys) | |||
156 | { | |||
157 | RestoreBkmks(rDoc, aUpdater); | |||
158 | RestoreRedlines(rDoc, aUpdater); | |||
159 | RestoreUnoCursors(aUpdater); | |||
160 | RestoreShellCursors(aUpdater); | |||
161 | } | |||
162 | if (eMode & RestoreMode::Flys) | |||
163 | { | |||
164 | RestoreFlys(rDoc, aUpdater, bAuto); | |||
165 | } | |||
166 | } | |||
167 | virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen, RestoreMode eMode = RestoreMode::All) override | |||
168 | { | |||
169 | SwContentNode* pCNd = rNd.GetContentNode(); | |||
170 | SwDoc& rDoc = rNd.GetDoc(); | |||
171 | updater_t aUpdater = LimitUpdater(pCNd, nLen, nCorrLen); | |||
172 | if (eMode & RestoreMode::NonFlys) | |||
173 | { | |||
174 | RestoreBkmks(rDoc, aUpdater); | |||
175 | RestoreRedlines(rDoc, aUpdater); | |||
176 | RestoreUnoCursors(aUpdater); | |||
177 | RestoreShellCursors(aUpdater); | |||
178 | } | |||
179 | if (eMode & RestoreMode::Flys) | |||
180 | { | |||
181 | RestoreFlys(rDoc, aUpdater, false); | |||
182 | } | |||
183 | } | |||
184 | ||||
185 | private: | |||
186 | void SaveBkmks(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent); | |||
187 | void RestoreBkmks(SwDoc& rDoc, updater_t const & rUpdater); | |||
188 | void SaveRedlines(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent); | |||
189 | void RestoreRedlines(SwDoc& rDoc, updater_t const & rUpdater); | |||
190 | void SaveFlys(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit); | |||
191 | void RestoreFlys(SwDoc& rDoc, updater_t const & rUpdater, bool bAuto); | |||
192 | void SaveUnoCursors(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent); | |||
193 | void RestoreUnoCursors(updater_t const & rUpdater); | |||
194 | void SaveShellCursors(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent); | |||
195 | void RestoreShellCursors(updater_t const & rUpdater); | |||
196 | static const SwPosition& GetRightMarkPos(::sw::mark::IMark const * pMark, bool bOther) | |||
197 | { return bOther ? pMark->GetOtherMarkPos() : pMark->GetMarkPos(); }; | |||
198 | static void SetRightMarkPos(MarkBase* pMark, bool bOther, const SwPosition* const pPos) | |||
199 | { bOther ? pMark->SetOtherMarkPos(*pPos) : pMark->SetMarkPos(*pPos); }; | |||
200 | }; | |||
201 | void lcl_ChkPaM( std::vector<PaMEntry>& rPaMEntries, const sal_uLong nNode, const sal_Int32 nContent, SwPaM& rPaM, const bool bGetPoint, bool bSetMark) | |||
202 | { | |||
203 | const SwPosition* pPos = &rPaM.GetBound(bGetPoint); | |||
204 | if( pPos->nNode.GetIndex() == nNode && pPos->nContent.GetIndex() < nContent ) | |||
205 | { | |||
206 | const PaMEntry aEntry = { &rPaM, bSetMark, pPos->nContent.GetIndex() }; | |||
207 | rPaMEntries.push_back(aEntry); | |||
208 | } | |||
209 | } | |||
210 | void lcl_ChkPaMBoth( std::vector<PaMEntry>& rPaMEntries, const sal_uLong nNode, const sal_Int32 nContent, SwPaM& rPaM) | |||
211 | { | |||
212 | lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, true, true); | |||
213 | lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, false, false); | |||
214 | } | |||
215 | void lcl_ChkUnoCrsrPaMBoth(std::vector<PaMEntry>& rPaMEntries, const sal_uLong nNode, const sal_Int32 nContent, SwPaM& rPaM) | |||
216 | { | |||
217 | lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, true, false); | |||
218 | lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, false, true); | |||
219 | } | |||
220 | ||||
221 | #if 0 | |||
222 | static void DumpEntries(std::vector<MarkEntry>* pEntries) | |||
223 | { | |||
224 | for (MarkEntry& aEntry : *pEntries) | |||
225 | aEntry.Dump(); | |||
226 | } | |||
227 | #endif | |||
228 | } | |||
229 | ||||
230 | void ContentIdxStoreImpl::SaveBkmks(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent) | |||
231 | { | |||
232 | IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); | |||
233 | const IDocumentMarkAccess::const_iterator_t ppBkmkEnd = pMarkAccess->getAllMarksEnd(); | |||
234 | for( | |||
235 | IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getAllMarksBegin(); | |||
236 | ppBkmk != ppBkmkEnd; | |||
237 | ++ppBkmk) | |||
238 | { | |||
239 | const ::sw::mark::IMark* pBkmk = *ppBkmk; | |||
240 | bool bMarkPosEqual = false; | |||
241 | if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode | |||
242 | && pBkmk->GetMarkPos().nContent.GetIndex() <= nContent) | |||
243 | { | |||
244 | if(pBkmk->GetMarkPos().nContent.GetIndex() < nContent) | |||
245 | { | |||
246 | const MarkEntry aEntry = { static_cast<long>(ppBkmk - pMarkAccess->getAllMarksBegin()), false, pBkmk->GetMarkPos().nContent.GetIndex() }; | |||
247 | m_aBkmkEntries.push_back(aEntry); | |||
248 | } | |||
249 | else // if a bookmark position is equal nContent, the other position | |||
250 | bMarkPosEqual = true; // has to decide if it is added to the array | |||
251 | } | |||
252 | if(pBkmk->IsExpanded() | |||
253 | && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode | |||
254 | && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nContent) | |||
255 | { | |||
256 | if(bMarkPosEqual) | |||
257 | { // the other position is before, the (main) position is equal | |||
258 | const MarkEntry aEntry = { static_cast<long>(ppBkmk - pMarkAccess->getAllMarksBegin()), false, pBkmk->GetMarkPos().nContent.GetIndex() }; | |||
259 | m_aBkmkEntries.push_back(aEntry); | |||
260 | } | |||
261 | const MarkEntry aEntry = { static_cast<long>(ppBkmk - pMarkAccess->getAllMarksBegin()), true, pBkmk->GetOtherMarkPos().nContent.GetIndex() }; | |||
262 | m_aBkmkEntries.push_back(aEntry); | |||
263 | } | |||
264 | } | |||
265 | } | |||
266 | ||||
267 | void ContentIdxStoreImpl::RestoreBkmks(SwDoc& rDoc, updater_t const & rUpdater) | |||
268 | { | |||
269 | IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); | |||
270 | for (const MarkEntry& aEntry : m_aBkmkEntries) | |||
271 | { | |||
272 | if (MarkBase *const pMark = pMarkAccess->getAllMarksBegin().get()[aEntry.m_nIdx]) | |||
273 | { | |||
274 | SwPosition aNewPos(GetRightMarkPos(pMark, aEntry.m_bOther)); | |||
275 | rUpdater(aNewPos, aEntry.m_nContent); | |||
276 | SetRightMarkPos(pMark, aEntry.m_bOther, &aNewPos); | |||
277 | } | |||
278 | } | |||
279 | if (!m_aBkmkEntries.empty()) | |||
280 | { // tdf#105705 sort bookmarks because SaveBkmks special handling of | |||
281 | // "bMarkPosEqual" may destroy sort order | |||
282 | pMarkAccess->assureSortedMarkContainers(); | |||
283 | } | |||
284 | } | |||
285 | ||||
286 | void ContentIdxStoreImpl::SaveRedlines(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent) | |||
287 | { | |||
288 | SwRedlineTable const & rRedlineTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); | |||
289 | long int nIdx = 0; | |||
290 | for (const SwRangeRedline* pRdl : rRedlineTable) | |||
291 | { | |||
292 | int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nContent ); | |||
293 | int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nContent ) : | |||
294 | nPointPos; | |||
295 | // #i59534: We have to store the positions inside the same node before the insert position | |||
296 | // and the one at the insert position if the corresponding Point/Mark position is before | |||
297 | // the insert position. | |||
298 | if( nPointPos == BEFORE_SAME_NODE || | |||
299 | ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) ) | |||
300 | { | |||
301 | const MarkEntry aEntry = { nIdx, false, pRdl->GetPoint()->nContent.GetIndex() }; | |||
302 | m_aRedlineEntries.push_back(aEntry); | |||
303 | } | |||
304 | if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE || | |||
305 | ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) ) | |||
306 | { | |||
307 | const MarkEntry aEntry = { nIdx, true, pRdl->GetMark()->nContent.GetIndex() }; | |||
308 | m_aRedlineEntries.push_back(aEntry); | |||
309 | } | |||
310 | ++nIdx; | |||
311 | } | |||
312 | } | |||
313 | ||||
314 | void ContentIdxStoreImpl::RestoreRedlines(SwDoc& rDoc, updater_t const & rUpdater) | |||
315 | { | |||
316 | const SwRedlineTable& rRedlTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); | |||
317 | for (const MarkEntry& aEntry : m_aRedlineEntries) | |||
318 | { | |||
319 | SwPosition* const pPos = aEntry.m_bOther | |||
320 | ? rRedlTable[ aEntry.m_nIdx ]->GetMark() | |||
321 | : rRedlTable[ aEntry.m_nIdx ]->GetPoint(); | |||
322 | rUpdater(*pPos, aEntry.m_nContent); | |||
323 | } | |||
324 | } | |||
325 | ||||
326 | void ContentIdxStoreImpl::SaveFlys(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit) | |||
327 | { | |||
328 | SwContentNode *pNode = rDoc.GetNodes()[nNode]->GetContentNode(); | |||
329 | if( !pNode ) | |||
330 | return; | |||
331 | SwFrame* pFrame = pNode->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() ); | |||
332 | if( pFrame ) | |||
333 | { | |||
334 | // sw_redlinehide: this looks like an invalid optimisation if merged, | |||
335 | // assuming that flys in deleted redlines should be saved here too. | |||
336 | if ((!pFrame->IsTextFrame() || !static_cast<SwTextFrame const*>(pFrame)->GetMergedPara()) | |||
337 | && !pFrame->GetDrawObjs()) | |||
338 | return; // if we have a layout and no DrawObjs, we can skip this | |||
339 | } | |||
340 | MarkEntry aSave = { 0, false, 0 }; | |||
341 | for (const SwFrameFormat* pFrameFormat : *rDoc.GetSpzFrameFormats()) | |||
342 | { | |||
343 | if ( RES_FLYFRMFMT == pFrameFormat->Which() || RES_DRAWFRMFMT == pFrameFormat->Which() ) | |||
344 | { | |||
345 | const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor(); | |||
346 | SwPosition const*const pAPos = rAnchor.GetContentAnchor(); | |||
347 | if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) && | |||
348 | ( RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() || | |||
349 | RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) | |||
350 | { | |||
351 | bool bSkip = false; | |||
352 | aSave.m_bOther = false; | |||
353 | aSave.m_nContent = pAPos->nContent.GetIndex(); | |||
354 | if ( RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() ) | |||
355 | { | |||
356 | if( nContent <= aSave.m_nContent ) | |||
357 | { | |||
358 | if( bSaveFlySplit ) | |||
359 | aSave.m_bOther = true; | |||
360 | else | |||
361 | bSkip = true; | |||
362 | } | |||
363 | } | |||
364 | if(!bSkip) | |||
365 | m_aFlyEntries.push_back(aSave); | |||
366 | } | |||
367 | } | |||
368 | ++aSave.m_nIdx; | |||
369 | } | |||
370 | } | |||
371 | ||||
372 | void ContentIdxStoreImpl::RestoreFlys(SwDoc& rDoc, updater_t const & rUpdater, bool bAuto) | |||
373 | { | |||
374 | SwFrameFormats* pSpz = rDoc.GetSpzFrameFormats(); | |||
375 | for (const MarkEntry& aEntry : m_aFlyEntries) | |||
376 | { | |||
377 | if(!aEntry.m_bOther) | |||
378 | { | |||
379 | SwFrameFormat *pFrameFormat = (*pSpz)[ aEntry.m_nIdx ]; | |||
380 | const SwFormatAnchor& rFlyAnchor = pFrameFormat->GetAnchor(); | |||
381 | if( rFlyAnchor.GetContentAnchor() ) | |||
382 | { | |||
383 | SwFormatAnchor aNew( rFlyAnchor ); | |||
384 | SwPosition aNewPos( *rFlyAnchor.GetContentAnchor() ); | |||
385 | rUpdater(aNewPos, aEntry.m_nContent); | |||
386 | if ( RndStdIds::FLY_AT_CHAR != rFlyAnchor.GetAnchorId() ) | |||
387 | { | |||
388 | aNewPos.nContent.Assign( nullptr, 0 ); | |||
389 | } | |||
390 | aNew.SetAnchor( &aNewPos ); | |||
391 | pFrameFormat->SetFormatAttr( aNew ); | |||
392 | } | |||
393 | } | |||
394 | else if( bAuto ) | |||
395 | { | |||
396 | SwFrameFormat *pFrameFormat = (*pSpz)[ aEntry.m_nIdx ]; | |||
397 | SfxPoolItem const *pAnchor = &pFrameFormat->GetAnchor(); | |||
398 | pFrameFormat->NotifyClients( pAnchor, pAnchor ); | |||
399 | } | |||
400 | } | |||
401 | } | |||
402 | ||||
403 | void ContentIdxStoreImpl::SaveUnoCursors(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent) | |||
404 | { | |||
405 | rDoc.cleanupUnoCursorTable(); | |||
406 | for (const auto& pWeakUnoCursor : rDoc.mvUnoCursorTable) | |||
407 | { | |||
408 | auto pUnoCursor(pWeakUnoCursor.lock()); | |||
409 | if(!pUnoCursor) | |||
410 | continue; | |||
411 | for(SwPaM& rPaM : pUnoCursor->GetRingContainer()) | |||
412 | { | |||
413 | lcl_ChkUnoCrsrPaMBoth(m_aUnoCursorEntries, nNode, nContent, rPaM); | |||
414 | } | |||
415 | const SwUnoTableCursor* pUnoTableCursor = dynamic_cast<const SwUnoTableCursor*>(pUnoCursor.get()); | |||
416 | if( pUnoTableCursor ) | |||
417 | { | |||
418 | for(SwPaM& rPaM : const_cast<SwUnoTableCursor*>(pUnoTableCursor)->GetSelRing().GetRingContainer()) | |||
419 | { | |||
420 | lcl_ChkUnoCrsrPaMBoth(m_aUnoCursorEntries, nNode, nContent, rPaM); | |||
421 | } | |||
422 | } | |||
423 | } | |||
424 | } | |||
425 | ||||
426 | void ContentIdxStoreImpl::RestoreUnoCursors(updater_t const & rUpdater) | |||
427 | { | |||
428 | for (const PaMEntry& aEntry : m_aUnoCursorEntries) | |||
429 | { | |||
430 | rUpdater(aEntry.m_pPaM->GetBound(!aEntry.m_isMark), aEntry.m_nContent); | |||
431 | } | |||
432 | } | |||
433 | ||||
434 | void ContentIdxStoreImpl::SaveShellCursors(SwDoc& rDoc, sal_uLong nNode, sal_Int32 nContent) | |||
435 | { | |||
436 | SwCursorShell* pShell = rDoc.GetEditShell(); | |||
437 | if( !pShell ) | |||
438 | return; | |||
439 | for(SwViewShell& rCurShell : pShell->GetRingContainer()) | |||
440 | { | |||
441 | if( dynamic_cast<const SwCursorShell *>(&rCurShell) != nullptr ) | |||
442 | { | |||
443 | SwPaM *_pStackCursor = static_cast<SwCursorShell*>(&rCurShell)->GetStackCursor(); | |||
444 | if( _pStackCursor ) | |||
445 | for (;;) | |||
446 | { | |||
447 | lcl_ChkPaMBoth( m_aShellCursorEntries, nNode, nContent, *_pStackCursor); | |||
448 | if (!_pStackCursor) | |||
449 | break; | |||
450 | _pStackCursor = _pStackCursor->GetNext(); | |||
451 | if (_pStackCursor == static_cast<SwCursorShell*>(&rCurShell)->GetStackCursor()) | |||
452 | break; | |||
453 | } | |||
454 | ||||
455 | for(SwPaM& rPaM : static_cast<SwCursorShell*>(&rCurShell)->GetCursor_()->GetRingContainer()) | |||
456 | { | |||
457 | lcl_ChkPaMBoth( m_aShellCursorEntries, nNode, nContent, rPaM); | |||
458 | } | |||
459 | } | |||
460 | } | |||
461 | } | |||
462 | ||||
463 | void ContentIdxStoreImpl::RestoreShellCursors(updater_t const & rUpdater) | |||
464 | { | |||
465 | for (const PaMEntry& aEntry : m_aShellCursorEntries) | |||
466 | { | |||
467 | rUpdater(aEntry.m_pPaM->GetBound(aEntry.m_isMark), aEntry.m_nContent); | |||
468 | } | |||
469 | } | |||
470 | ||||
471 | namespace sw::mark { | |||
472 | std::shared_ptr<ContentIdxStore> ContentIdxStore::Create() | |||
473 | { | |||
474 | return std::make_shared<ContentIdxStoreImpl>(); | |||
475 | } | |||
476 | } | |||
477 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | // Implementation of std::function -*- C++ -*- |
2 | |
3 | // Copyright (C) 2004-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/bits/std_function.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{functional} |
28 | */ |
29 | |
30 | #ifndef _GLIBCXX_STD_FUNCTION_H1 |
31 | #define _GLIBCXX_STD_FUNCTION_H1 1 |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus201703L < 201103L |
36 | # include <bits/c++0x_warning.h> |
37 | #else |
38 | |
39 | #if __cpp_rtti199711L |
40 | # include <typeinfo> |
41 | #endif |
42 | #include <bits/stl_function.h> |
43 | #include <bits/invoke.h> |
44 | #include <bits/refwrap.h> |
45 | #include <bits/functexcept.h> |
46 | |
47 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
48 | { |
49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
50 | |
51 | /** |
52 | * @brief Exception class thrown when class template function's |
53 | * operator() is called with an empty target. |
54 | * @ingroup exceptions |
55 | */ |
56 | class bad_function_call : public std::exception |
57 | { |
58 | public: |
59 | virtual ~bad_function_call() noexcept; |
60 | |
61 | const char* what() const noexcept; |
62 | }; |
63 | |
64 | /** |
65 | * Trait identifying "location-invariant" types, meaning that the |
66 | * address of the object (or any of its members) will not escape. |
67 | * Trivially copyable types are location-invariant and users can |
68 | * specialize this trait for other types. |
69 | */ |
70 | template<typename _Tp> |
71 | struct __is_location_invariant |
72 | : is_trivially_copyable<_Tp>::type |
73 | { }; |
74 | |
75 | class _Undefined_class; |
76 | |
77 | union _Nocopy_types |
78 | { |
79 | void* _M_object; |
80 | const void* _M_const_object; |
81 | void (*_M_function_pointer)(); |
82 | void (_Undefined_class::*_M_member_pointer)(); |
83 | }; |
84 | |
85 | union [[gnu::may_alias]] _Any_data |
86 | { |
87 | void* _M_access() { return &_M_pod_data[0]; } |
88 | const void* _M_access() const { return &_M_pod_data[0]; } |
89 | |
90 | template<typename _Tp> |
91 | _Tp& |
92 | _M_access() |
93 | { return *static_cast<_Tp*>(_M_access()); } |
94 | |
95 | template<typename _Tp> |
96 | const _Tp& |
97 | _M_access() const |
98 | { return *static_cast<const _Tp*>(_M_access()); } |
99 | |
100 | _Nocopy_types _M_unused; |
101 | char _M_pod_data[sizeof(_Nocopy_types)]; |
102 | }; |
103 | |
104 | enum _Manager_operation |
105 | { |
106 | __get_type_info, |
107 | __get_functor_ptr, |
108 | __clone_functor, |
109 | __destroy_functor |
110 | }; |
111 | |
112 | template<typename _Signature> |
113 | class function; |
114 | |
115 | /// Base class of all polymorphic function object wrappers. |
116 | class _Function_base |
117 | { |
118 | public: |
119 | static const size_t _M_max_size = sizeof(_Nocopy_types); |
120 | static const size_t _M_max_align = __alignof__(_Nocopy_types); |
121 | |
122 | template<typename _Functor> |
123 | class _Base_manager |
124 | { |
125 | protected: |
126 | static const bool __stored_locally = |
127 | (__is_location_invariant<_Functor>::value |
128 | && sizeof(_Functor) <= _M_max_size |
129 | && __alignof__(_Functor) <= _M_max_align |
130 | && (_M_max_align % __alignof__(_Functor) == 0)); |
131 | |
132 | typedef integral_constant<bool, __stored_locally> _Local_storage; |
133 | |
134 | // Retrieve a pointer to the function object |
135 | static _Functor* |
136 | _M_get_pointer(const _Any_data& __source) |
137 | { |
138 | if _GLIBCXX17_CONSTEXPRconstexpr (__stored_locally) |
139 | { |
140 | const _Functor& __f = __source._M_access<_Functor>(); |
141 | return const_cast<_Functor*>(std::__addressof(__f)); |
142 | } |
143 | else // have stored a pointer |
144 | return __source._M_access<_Functor*>(); |
145 | } |
146 | |
147 | // Clone a location-invariant function object that fits within |
148 | // an _Any_data structure. |
149 | static void |
150 | _M_clone(_Any_data& __dest, const _Any_data& __source, true_type) |
151 | { |
152 | ::new (__dest._M_access()) _Functor(__source._M_access<_Functor>()); |
153 | } |
154 | |
155 | // Clone a function object that is not location-invariant or |
156 | // that cannot fit into an _Any_data structure. |
157 | static void |
158 | _M_clone(_Any_data& __dest, const _Any_data& __source, false_type) |
159 | { |
160 | __dest._M_access<_Functor*>() = |
161 | new _Functor(*__source._M_access<const _Functor*>()); |
162 | } |
163 | |
164 | // Destroying a location-invariant object may still require |
165 | // destruction. |
166 | static void |
167 | _M_destroy(_Any_data& __victim, true_type) |
168 | { |
169 | __victim._M_access<_Functor>().~_Functor(); |
170 | } |
171 | |
172 | // Destroying an object located on the heap. |
173 | static void |
174 | _M_destroy(_Any_data& __victim, false_type) |
175 | { |
176 | delete __victim._M_access<_Functor*>(); |
177 | } |
178 | |
179 | public: |
180 | static bool |
181 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
182 | _Manager_operation __op) |
183 | { |
184 | switch (__op) |
185 | { |
186 | #if __cpp_rtti199711L |
187 | case __get_type_info: |
188 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
189 | break; |
190 | #endif |
191 | case __get_functor_ptr: |
192 | __dest._M_access<_Functor*>() = _M_get_pointer(__source); |
193 | break; |
194 | |
195 | case __clone_functor: |
196 | _M_clone(__dest, __source, _Local_storage()); |
197 | break; |
198 | |
199 | case __destroy_functor: |
200 | _M_destroy(__dest, _Local_storage()); |
201 | break; |
202 | } |
203 | return false; |
204 | } |
205 | |
206 | static void |
207 | _M_init_functor(_Any_data& __functor, _Functor&& __f) |
208 | { _M_init_functor(__functor, std::move(__f), _Local_storage()); } |
209 | |
210 | template<typename _Signature> |
211 | static bool |
212 | _M_not_empty_function(const function<_Signature>& __f) |
213 | { return static_cast<bool>(__f); } |
214 | |
215 | template<typename _Tp> |
216 | static bool |
217 | _M_not_empty_function(_Tp* __fp) |
218 | { return __fp != nullptr; } |
219 | |
220 | template<typename _Class, typename _Tp> |
221 | static bool |
222 | _M_not_empty_function(_Tp _Class::* __mp) |
223 | { return __mp != nullptr; } |
224 | |
225 | template<typename _Tp> |
226 | static bool |
227 | _M_not_empty_function(const _Tp&) |
228 | { return true; } |
229 | |
230 | private: |
231 | static void |
232 | _M_init_functor(_Any_data& __functor, _Functor&& __f, true_type) |
233 | { ::new (__functor._M_access()) _Functor(std::move(__f)); } |
234 | |
235 | static void |
236 | _M_init_functor(_Any_data& __functor, _Functor&& __f, false_type) |
237 | { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); } |
238 | }; |
239 | |
240 | _Function_base() : _M_manager(nullptr) { } |
241 | |
242 | ~_Function_base() |
243 | { |
244 | if (_M_manager) |
245 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
246 | } |
247 | |
248 | bool _M_empty() const { return !_M_manager; } |
249 | |
250 | typedef bool (*_Manager_type)(_Any_data&, const _Any_data&, |
251 | _Manager_operation); |
252 | |
253 | _Any_data _M_functor; |
254 | _Manager_type _M_manager; |
255 | }; |
256 | |
257 | template<typename _Signature, typename _Functor> |
258 | class _Function_handler; |
259 | |
260 | template<typename _Res, typename _Functor, typename... _ArgTypes> |
261 | class _Function_handler<_Res(_ArgTypes...), _Functor> |
262 | : public _Function_base::_Base_manager<_Functor> |
263 | { |
264 | typedef _Function_base::_Base_manager<_Functor> _Base; |
265 | |
266 | public: |
267 | static bool |
268 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
269 | _Manager_operation __op) |
270 | { |
271 | switch (__op) |
272 | { |
273 | #if __cpp_rtti199711L |
274 | case __get_type_info: |
275 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
276 | break; |
277 | #endif |
278 | case __get_functor_ptr: |
279 | __dest._M_access<_Functor*>() = _Base::_M_get_pointer(__source); |
280 | break; |
281 | |
282 | default: |
283 | _Base::_M_manager(__dest, __source, __op); |
284 | } |
285 | return false; |
286 | } |
287 | |
288 | static _Res |
289 | _M_invoke(const _Any_data& __functor, _ArgTypes&&... __args) |
290 | { |
291 | return std::__invoke_r<_Res>(*_Base::_M_get_pointer(__functor), |
292 | std::forward<_ArgTypes>(__args)...); |
293 | } |
294 | }; |
295 | |
296 | /** |
297 | * @brief Primary class template for std::function. |
298 | * @ingroup functors |
299 | * |
300 | * Polymorphic function wrapper. |
301 | */ |
302 | template<typename _Res, typename... _ArgTypes> |
303 | class function<_Res(_ArgTypes...)> |
304 | : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, |
305 | private _Function_base |
306 | { |
307 | template<typename _Func, |
308 | typename _Res2 = __invoke_result<_Func&, _ArgTypes...>> |
309 | struct _Callable |
310 | : __is_invocable_impl<_Res2, _Res>::type |
311 | { }; |
312 | |
313 | // Used so the return type convertibility checks aren't done when |
314 | // performing overload resolution for copy construction/assignment. |
315 | template<typename _Tp> |
316 | struct _Callable<function, _Tp> : false_type { }; |
317 | |
318 | template<typename _Cond, typename _Tp> |
319 | using _Requires = typename enable_if<_Cond::value, _Tp>::type; |
320 | |
321 | public: |
322 | typedef _Res result_type; |
323 | |
324 | // [3.7.2.1] construct/copy/destroy |
325 | |
326 | /** |
327 | * @brief Default construct creates an empty function call wrapper. |
328 | * @post @c !(bool)*this |
329 | */ |
330 | function() noexcept |
331 | : _Function_base() { } |
332 | |
333 | /** |
334 | * @brief Creates an empty function call wrapper. |
335 | * @post @c !(bool)*this |
336 | */ |
337 | function(nullptr_t) noexcept |
338 | : _Function_base() { } |
339 | |
340 | /** |
341 | * @brief %Function copy constructor. |
342 | * @param __x A %function object with identical call signature. |
343 | * @post @c bool(*this) == bool(__x) |
344 | * |
345 | * The newly-created %function contains a copy of the target of @a |
346 | * __x (if it has one). |
347 | */ |
348 | function(const function& __x); |
349 | |
350 | /** |
351 | * @brief %Function move constructor. |
352 | * @param __x A %function object rvalue with identical call signature. |
353 | * |
354 | * The newly-created %function contains the target of @a __x |
355 | * (if it has one). |
356 | */ |
357 | function(function&& __x) noexcept : _Function_base() |
358 | { |
359 | __x.swap(*this); |
360 | } |
361 | |
362 | /** |
363 | * @brief Builds a %function that targets a copy of the incoming |
364 | * function object. |
365 | * @param __f A %function object that is callable with parameters of |
366 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
367 | * to @c Res. |
368 | * |
369 | * The newly-created %function object will target a copy of |
370 | * @a __f. If @a __f is @c reference_wrapper<F>, then this function |
371 | * object will contain a reference to the function object @c |
372 | * __f.get(). If @a __f is a NULL function pointer or NULL |
373 | * pointer-to-member, the newly-created object will be empty. |
374 | * |
375 | * If @a __f is a non-NULL function pointer or an object of type @c |
376 | * reference_wrapper<F>, this function will not throw. |
377 | */ |
378 | template<typename _Functor, |
379 | typename = _Requires<__not_<is_same<_Functor, function>>, void>, |
380 | typename = _Requires<_Callable<_Functor>, void>> |
381 | function(_Functor); |
382 | |
383 | /** |
384 | * @brief %Function assignment operator. |
385 | * @param __x A %function with identical call signature. |
386 | * @post @c (bool)*this == (bool)x |
387 | * @returns @c *this |
388 | * |
389 | * The target of @a __x is copied to @c *this. If @a __x has no |
390 | * target, then @c *this will be empty. |
391 | * |
392 | * If @a __x targets a function pointer or a reference to a function |
393 | * object, then this operation will not throw an %exception. |
394 | */ |
395 | function& |
396 | operator=(const function& __x) |
397 | { |
398 | function(__x).swap(*this); |
399 | return *this; |
400 | } |
401 | |
402 | /** |
403 | * @brief %Function move-assignment operator. |
404 | * @param __x A %function rvalue with identical call signature. |
405 | * @returns @c *this |
406 | * |
407 | * The target of @a __x is moved to @c *this. If @a __x has no |
408 | * target, then @c *this will be empty. |
409 | * |
410 | * If @a __x targets a function pointer or a reference to a function |
411 | * object, then this operation will not throw an %exception. |
412 | */ |
413 | function& |
414 | operator=(function&& __x) noexcept |
415 | { |
416 | function(std::move(__x)).swap(*this); |
417 | return *this; |
418 | } |
419 | |
420 | /** |
421 | * @brief %Function assignment to zero. |
422 | * @post @c !(bool)*this |
423 | * @returns @c *this |
424 | * |
425 | * The target of @c *this is deallocated, leaving it empty. |
426 | */ |
427 | function& |
428 | operator=(nullptr_t) noexcept |
429 | { |
430 | if (_M_manager) |
431 | { |
432 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
433 | _M_manager = nullptr; |
434 | _M_invoker = nullptr; |
435 | } |
436 | return *this; |
437 | } |
438 | |
439 | /** |
440 | * @brief %Function assignment to a new target. |
441 | * @param __f A %function object that is callable with parameters of |
442 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
443 | * to @c Res. |
444 | * @return @c *this |
445 | * |
446 | * This %function object wrapper will target a copy of @a |
447 | * __f. If @a __f is @c reference_wrapper<F>, then this function |
448 | * object will contain a reference to the function object @c |
449 | * __f.get(). If @a __f is a NULL function pointer or NULL |
450 | * pointer-to-member, @c this object will be empty. |
451 | * |
452 | * If @a __f is a non-NULL function pointer or an object of type @c |
453 | * reference_wrapper<F>, this function will not throw. |
454 | */ |
455 | template<typename _Functor> |
456 | _Requires<_Callable<typename decay<_Functor>::type>, function&> |
457 | operator=(_Functor&& __f) |
458 | { |
459 | function(std::forward<_Functor>(__f)).swap(*this); |
460 | return *this; |
461 | } |
462 | |
463 | /// @overload |
464 | template<typename _Functor> |
465 | function& |
466 | operator=(reference_wrapper<_Functor> __f) noexcept |
467 | { |
468 | function(__f).swap(*this); |
469 | return *this; |
470 | } |
471 | |
472 | // [3.7.2.2] function modifiers |
473 | |
474 | /** |
475 | * @brief Swap the targets of two %function objects. |
476 | * @param __x A %function with identical call signature. |
477 | * |
478 | * Swap the targets of @c this function object and @a __f. This |
479 | * function will not throw an %exception. |
480 | */ |
481 | void swap(function& __x) noexcept |
482 | { |
483 | std::swap(_M_functor, __x._M_functor); |
484 | std::swap(_M_manager, __x._M_manager); |
485 | std::swap(_M_invoker, __x._M_invoker); |
486 | } |
487 | |
488 | // [3.7.2.3] function capacity |
489 | |
490 | /** |
491 | * @brief Determine if the %function wrapper has a target. |
492 | * |
493 | * @return @c true when this %function object contains a target, |
494 | * or @c false when it is empty. |
495 | * |
496 | * This function will not throw an %exception. |
497 | */ |
498 | explicit operator bool() const noexcept |
499 | { return !_M_empty(); } |
500 | |
501 | // [3.7.2.4] function invocation |
502 | |
503 | /** |
504 | * @brief Invokes the function targeted by @c *this. |
505 | * @returns the result of the target. |
506 | * @throws bad_function_call when @c !(bool)*this |
507 | * |
508 | * The function call operator invokes the target function object |
509 | * stored by @c this. |
510 | */ |
511 | _Res operator()(_ArgTypes... __args) const; |
512 | |
513 | #if __cpp_rtti199711L |
514 | // [3.7.2.5] function target access |
515 | /** |
516 | * @brief Determine the type of the target of this function object |
517 | * wrapper. |
518 | * |
519 | * @returns the type identifier of the target function object, or |
520 | * @c typeid(void) if @c !(bool)*this. |
521 | * |
522 | * This function will not throw an %exception. |
523 | */ |
524 | const type_info& target_type() const noexcept; |
525 | |
526 | /** |
527 | * @brief Access the stored target function object. |
528 | * |
529 | * @return Returns a pointer to the stored target function object, |
530 | * if @c typeid(_Functor).equals(target_type()); otherwise, a NULL |
531 | * pointer. |
532 | * |
533 | * This function does not throw exceptions. |
534 | * |
535 | * @{ |
536 | */ |
537 | template<typename _Functor> _Functor* target() noexcept; |
538 | |
539 | template<typename _Functor> const _Functor* target() const noexcept; |
540 | // @} |
541 | #endif |
542 | |
543 | private: |
544 | using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...); |
545 | _Invoker_type _M_invoker; |
546 | }; |
547 | |
548 | #if __cpp_deduction_guides201703L >= 201606 |
549 | template<typename> |
550 | struct __function_guide_helper |
551 | { }; |
552 | |
553 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
554 | struct __function_guide_helper< |
555 | _Res (_Tp::*) (_Args...) noexcept(_Nx) |
556 | > |
557 | { using type = _Res(_Args...); }; |
558 | |
559 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
560 | struct __function_guide_helper< |
561 | _Res (_Tp::*) (_Args...) & noexcept(_Nx) |
562 | > |
563 | { using type = _Res(_Args...); }; |
564 | |
565 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
566 | struct __function_guide_helper< |
567 | _Res (_Tp::*) (_Args...) const noexcept(_Nx) |
568 | > |
569 | { using type = _Res(_Args...); }; |
570 | |
571 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
572 | struct __function_guide_helper< |
573 | _Res (_Tp::*) (_Args...) const & noexcept(_Nx) |
574 | > |
575 | { using type = _Res(_Args...); }; |
576 | |
577 | template<typename _Res, typename... _ArgTypes> |
578 | function(_Res(*)(_ArgTypes...)) -> function<_Res(_ArgTypes...)>; |
579 | |
580 | template<typename _Functor, typename _Signature = typename |
581 | __function_guide_helper<decltype(&_Functor::operator())>::type> |
582 | function(_Functor) -> function<_Signature>; |
583 | #endif |
584 | |
585 | // Out-of-line member definitions. |
586 | template<typename _Res, typename... _ArgTypes> |
587 | function<_Res(_ArgTypes...)>:: |
588 | function(const function& __x) |
589 | : _Function_base() |
590 | { |
591 | if (static_cast<bool>(__x)) |
592 | { |
593 | __x._M_manager(_M_functor, __x._M_functor, __clone_functor); |
594 | _M_invoker = __x._M_invoker; |
595 | _M_manager = __x._M_manager; |
596 | } |
597 | } |
598 | |
599 | template<typename _Res, typename... _ArgTypes> |
600 | template<typename _Functor, typename, typename> |
601 | function<_Res(_ArgTypes...)>:: |
602 | function(_Functor __f) |
603 | : _Function_base() |
604 | { |
605 | typedef _Function_handler<_Res(_ArgTypes...), _Functor> _My_handler; |
606 | |
607 | if (_My_handler::_M_not_empty_function(__f)) |
608 | { |
609 | _My_handler::_M_init_functor(_M_functor, std::move(__f)); |
610 | _M_invoker = &_My_handler::_M_invoke; |
611 | _M_manager = &_My_handler::_M_manager; |
612 | } |
613 | } |
614 | |
615 | template<typename _Res, typename... _ArgTypes> |
616 | _Res |
617 | function<_Res(_ArgTypes...)>:: |
618 | operator()(_ArgTypes... __args) const |
619 | { |
620 | if (_M_empty()) |
621 | __throw_bad_function_call(); |
622 | return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...); |
623 | } |
624 | |
625 | #if __cpp_rtti199711L |
626 | template<typename _Res, typename... _ArgTypes> |
627 | const type_info& |
628 | function<_Res(_ArgTypes...)>:: |
629 | target_type() const noexcept |
630 | { |
631 | if (_M_manager) |
632 | { |
633 | _Any_data __typeinfo_result; |
634 | _M_manager(__typeinfo_result, _M_functor, __get_type_info); |
635 | return *__typeinfo_result._M_access<const type_info*>(); |
636 | } |
637 | else |
638 | return typeid(void); |
639 | } |
640 | |
641 | template<typename _Res, typename... _ArgTypes> |
642 | template<typename _Functor> |
643 | _Functor* |
644 | function<_Res(_ArgTypes...)>:: |
645 | target() noexcept |
646 | { |
647 | const function* __const_this = this; |
648 | const _Functor* __func = __const_this->template target<_Functor>(); |
649 | return const_cast<_Functor*>(__func); |
650 | } |
651 | |
652 | template<typename _Res, typename... _ArgTypes> |
653 | template<typename _Functor> |
654 | const _Functor* |
655 | function<_Res(_ArgTypes...)>:: |
656 | target() const noexcept |
657 | { |
658 | if (typeid(_Functor) == target_type() && _M_manager) |
659 | { |
660 | _Any_data __ptr; |
661 | _M_manager(__ptr, _M_functor, __get_functor_ptr); |
662 | return __ptr._M_access<const _Functor*>(); |
663 | } |
664 | else |
665 | return nullptr; |
666 | } |
667 | #endif |
668 | |
669 | // [20.7.15.2.6] null pointer comparisons |
670 | |
671 | /** |
672 | * @brief Compares a polymorphic function object wrapper against 0 |
673 | * (the NULL pointer). |
674 | * @returns @c true if the wrapper has no target, @c false otherwise |
675 | * |
676 | * This function will not throw an %exception. |
677 | */ |
678 | template<typename _Res, typename... _Args> |
679 | inline bool |
680 | operator==(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
681 | { return !static_cast<bool>(__f); } |
682 | |
683 | #if __cpp_impl_three_way_comparison < 201907L |
684 | /// @overload |
685 | template<typename _Res, typename... _Args> |
686 | inline bool |
687 | operator==(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
688 | { return !static_cast<bool>(__f); } |
689 | |
690 | /** |
691 | * @brief Compares a polymorphic function object wrapper against 0 |
692 | * (the NULL pointer). |
693 | * @returns @c false if the wrapper has no target, @c true otherwise |
694 | * |
695 | * This function will not throw an %exception. |
696 | */ |
697 | template<typename _Res, typename... _Args> |
698 | inline bool |
699 | operator!=(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
700 | { return static_cast<bool>(__f); } |
701 | |
702 | /// @overload |
703 | template<typename _Res, typename... _Args> |
704 | inline bool |
705 | operator!=(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
706 | { return static_cast<bool>(__f); } |
707 | #endif |
708 | |
709 | // [20.7.15.2.7] specialized algorithms |
710 | |
711 | /** |
712 | * @brief Swap the targets of two polymorphic function object wrappers. |
713 | * |
714 | * This function will not throw an %exception. |
715 | */ |
716 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
717 | // 2062. Effect contradictions w/o no-throw guarantee of std::function swaps |
718 | template<typename _Res, typename... _Args> |
719 | inline void |
720 | swap(function<_Res(_Args...)>& __x, function<_Res(_Args...)>& __y) noexcept |
721 | { __x.swap(__y); } |
722 | |
723 | #if __cplusplus201703L >= 201703L |
724 | namespace __detail::__variant |
725 | { |
726 | template<typename> struct _Never_valueless_alt; // see <variant> |
727 | |
728 | // Provide the strong exception-safety guarantee when emplacing a |
729 | // function into a variant. |
730 | template<typename _Signature> |
731 | struct _Never_valueless_alt<std::function<_Signature>> |
732 | : std::true_type |
733 | { }; |
734 | } // namespace __detail::__variant |
735 | #endif // C++17 |
736 | |
737 | _GLIBCXX_END_NAMESPACE_VERSION |
738 | } // namespace std |
739 | |
740 | #endif // C++11 |
741 | #endif // _GLIBCXX_STD_FUNCTION_H |
1 | // Implementation of INVOKE -*- C++ -*- | ||||||
2 | |||||||
3 | // Copyright (C) 2016-2020 Free Software Foundation, Inc. | ||||||
4 | // | ||||||
5 | // This file is part of the GNU ISO C++ Library. This library is free | ||||||
6 | // software; you can redistribute it and/or modify it under the | ||||||
7 | // terms of the GNU General Public License as published by the | ||||||
8 | // Free Software Foundation; either version 3, or (at your option) | ||||||
9 | // any later version. | ||||||
10 | |||||||
11 | // This library is distributed in the hope that it will be useful, | ||||||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
14 | // GNU General Public License for more details. | ||||||
15 | |||||||
16 | // Under Section 7 of GPL version 3, you are granted additional | ||||||
17 | // permissions described in the GCC Runtime Library Exception, version | ||||||
18 | // 3.1, as published by the Free Software Foundation. | ||||||
19 | |||||||
20 | // You should have received a copy of the GNU General Public License and | ||||||
21 | // a copy of the GCC Runtime Library Exception along with this program; | ||||||
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | ||||||
23 | // <http://www.gnu.org/licenses/>. | ||||||
24 | |||||||
25 | /** @file include/bits/invoke.h | ||||||
26 | * This is an internal header file, included by other library headers. | ||||||
27 | * Do not attempt to use it directly. @headername{functional} | ||||||
28 | */ | ||||||
29 | |||||||
30 | #ifndef _GLIBCXX_INVOKE_H1 | ||||||
31 | #define _GLIBCXX_INVOKE_H1 1 | ||||||
32 | |||||||
33 | #pragma GCC system_header | ||||||
34 | |||||||
35 | #if __cplusplus201703L < 201103L | ||||||
36 | # include <bits/c++0x_warning.h> | ||||||
37 | #else | ||||||
38 | |||||||
39 | #include <type_traits> | ||||||
40 | |||||||
41 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) | ||||||
42 | { | ||||||
43 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | ||||||
44 | |||||||
45 | /** | ||||||
46 | * @addtogroup utilities | ||||||
47 | * @{ | ||||||
48 | */ | ||||||
49 | |||||||
50 | // Used by __invoke_impl instead of std::forward<_Tp> so that a | ||||||
51 | // reference_wrapper is converted to an lvalue-reference. | ||||||
52 | template<typename _Tp, typename _Up = typename __inv_unwrap<_Tp>::type> | ||||||
53 | constexpr _Up&& | ||||||
54 | __invfwd(typename remove_reference<_Tp>::type& __t) noexcept | ||||||
55 | { return static_cast<_Up&&>(__t); } | ||||||
56 | |||||||
57 | template<typename _Res, typename _Fn, typename... _Args> | ||||||
58 | constexpr _Res | ||||||
59 | __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) | ||||||
60 | { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } | ||||||
61 | |||||||
62 | template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> | ||||||
63 | constexpr _Res | ||||||
64 | __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, | ||||||
65 | _Args&&... __args) | ||||||
66 | { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } | ||||||
67 | |||||||
68 | template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> | ||||||
69 | constexpr _Res | ||||||
70 | __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, | ||||||
71 | _Args&&... __args) | ||||||
72 | { | ||||||
73 | return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...); | ||||||
74 | } | ||||||
75 | |||||||
76 | template<typename _Res, typename _MemPtr, typename _Tp> | ||||||
77 | constexpr _Res | ||||||
78 | __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t) | ||||||
79 | { return __invfwd<_Tp>(__t).*__f; } | ||||||
80 | |||||||
81 | template<typename _Res, typename _MemPtr, typename _Tp> | ||||||
82 | constexpr _Res | ||||||
83 | __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t) | ||||||
84 | { return (*std::forward<_Tp>(__t)).*__f; } | ||||||
85 | |||||||
86 | /// Invoke a callable object. | ||||||
87 | template<typename _Callable, typename... _Args> | ||||||
88 | constexpr typename __invoke_result<_Callable, _Args...>::type | ||||||
89 | __invoke(_Callable&& __fn, _Args&&... __args) | ||||||
90 | noexcept(__is_nothrow_invocable<_Callable, _Args...>::value) | ||||||
91 | { | ||||||
92 | using __result = __invoke_result<_Callable, _Args...>; | ||||||
93 | using __type = typename __result::type; | ||||||
94 | using __tag = typename __result::__invoke_type; | ||||||
95 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), | ||||||
96 | std::forward<_Args>(__args)...); | ||||||
97 | } | ||||||
98 | |||||||
99 | #if __cplusplus201703L >= 201703L | ||||||
100 | // INVOKE<R>: Invoke a callable object and convert the result to R. | ||||||
101 | template<typename _Res, typename _Callable, typename... _Args> | ||||||
102 | constexpr enable_if_t<is_invocable_r_v<_Res, _Callable, _Args...>, _Res> | ||||||
103 | __invoke_r(_Callable&& __fn, _Args&&... __args) | ||||||
104 | noexcept(is_nothrow_invocable_r_v<_Res, _Callable, _Args...>) | ||||||
105 | { | ||||||
106 | using __result = __invoke_result<_Callable, _Args...>; | ||||||
107 | using __type = typename __result::type; | ||||||
108 | using __tag = typename __result::__invoke_type; | ||||||
109 | if constexpr (is_void_v<_Res>
| ||||||
110 | std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), | ||||||
111 | std::forward<_Args>(__args)...); | ||||||
112 | else | ||||||
113 | return std::__invoke_impl<__type>(__tag{}, | ||||||
114 | std::forward<_Callable>(__fn), | ||||||
115 | std::forward<_Args>(__args)...); | ||||||
116 | } | ||||||
117 | #else // C++11 | ||||||
118 | template<typename _Res, typename _Callable, typename... _Args> | ||||||
119 | using __can_invoke_as_void = __enable_if_t< | ||||||
120 | __and_<is_void<_Res>, __is_invocable<_Callable, _Args...>>::value, | ||||||
121 | _Res | ||||||
122 | >; | ||||||
123 | |||||||
124 | template<typename _Res, typename _Callable, typename... _Args> | ||||||
125 | using __can_invoke_as_nonvoid = __enable_if_t< | ||||||
126 | __and_<__not_<is_void<_Res>>, | ||||||
127 | is_convertible<typename __invoke_result<_Callable, _Args...>::type, | ||||||
128 | _Res> | ||||||
129 | >::value, | ||||||
130 | _Res | ||||||
131 | >; | ||||||
132 | |||||||
133 | // INVOKE<R>: Invoke a callable object and convert the result to R. | ||||||
134 | template<typename _Res, typename _Callable, typename... _Args> | ||||||
135 | constexpr __can_invoke_as_nonvoid<_Res, _Callable, _Args...> | ||||||
136 | __invoke_r(_Callable&& __fn, _Args&&... __args) | ||||||
137 | { | ||||||
138 | using __result = __invoke_result<_Callable, _Args...>; | ||||||
139 | using __type = typename __result::type; | ||||||
140 | using __tag = typename __result::__invoke_type; | ||||||
141 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), | ||||||
142 | std::forward<_Args>(__args)...); | ||||||
143 | } | ||||||
144 | |||||||
145 | // INVOKE<R> when R is cv void | ||||||
146 | template<typename _Res, typename _Callable, typename... _Args> | ||||||
147 | _GLIBCXX14_CONSTEXPRconstexpr __can_invoke_as_void<_Res, _Callable, _Args...> | ||||||
148 | __invoke_r(_Callable&& __fn, _Args&&... __args) | ||||||
149 | { | ||||||
150 | using __result = __invoke_result<_Callable, _Args...>; | ||||||
151 | using __type = typename __result::type; | ||||||
152 | using __tag = typename __result::__invoke_type; | ||||||
153 | std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), | ||||||
154 | std::forward<_Args>(__args)...); | ||||||
155 | } | ||||||
156 | #endif // C++11 | ||||||
157 | |||||||
158 | _GLIBCXX_END_NAMESPACE_VERSION | ||||||
159 | } // namespace std | ||||||
160 | |||||||
161 | #endif // C++11 | ||||||
162 | |||||||
163 | #endif // _GLIBCXX_INVOKE_H |