File: | home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx |
Warning: | line 2852, column 5 Assigned value is garbage or undefined |
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 <comphelper/processfactory.hxx> | ||||
21 | #include <comphelper/random.hxx> | ||||
22 | #include <unotools/textsearch.hxx> | ||||
23 | #include <svl/zforlist.hxx> | ||||
24 | #include <svl/zformat.hxx> | ||||
25 | #include <unotools/charclass.hxx> | ||||
26 | #include <unotools/collatorwrapper.hxx> | ||||
27 | #include <stdlib.h> | ||||
28 | #include <unotools/transliterationwrapper.hxx> | ||||
29 | #include <com/sun/star/i18n/KParseTokens.hpp> | ||||
30 | #include <com/sun/star/i18n/KParseType.hpp> | ||||
31 | #include <sal/log.hxx> | ||||
32 | |||||
33 | #include <refdata.hxx> | ||||
34 | #include <table.hxx> | ||||
35 | #include <scitems.hxx> | ||||
36 | #include <formulacell.hxx> | ||||
37 | #include <document.hxx> | ||||
38 | #include <globstr.hrc> | ||||
39 | #include <scresid.hxx> | ||||
40 | #include <global.hxx> | ||||
41 | #include <stlpool.hxx> | ||||
42 | #include <patattr.hxx> | ||||
43 | #include <subtotal.hxx> | ||||
44 | #include <docoptio.hxx> | ||||
45 | #include <markdata.hxx> | ||||
46 | #include <rangelst.hxx> | ||||
47 | #include <userlist.hxx> | ||||
48 | #include <progress.hxx> | ||||
49 | #include <cellform.hxx> | ||||
50 | #include <queryparam.hxx> | ||||
51 | #include <queryentry.hxx> | ||||
52 | #include <subtotalparam.hxx> | ||||
53 | #include <docpool.hxx> | ||||
54 | #include <cellvalue.hxx> | ||||
55 | #include <tokenarray.hxx> | ||||
56 | #include <mtvcellfunc.hxx> | ||||
57 | #include <columnspanset.hxx> | ||||
58 | #include <fstalgorithm.hxx> | ||||
59 | #include <listenercontext.hxx> | ||||
60 | #include <sharedformula.hxx> | ||||
61 | #include <stlsheet.hxx> | ||||
62 | #include <refhint.hxx> | ||||
63 | #include <listenerquery.hxx> | ||||
64 | #include <bcaslot.hxx> | ||||
65 | #include <reordermap.hxx> | ||||
66 | #include <drwlayer.hxx> | ||||
67 | |||||
68 | #include <svl/sharedstringpool.hxx> | ||||
69 | |||||
70 | #include <memory> | ||||
71 | #include <set> | ||||
72 | #include <unordered_set> | ||||
73 | #include <vector> | ||||
74 | #include <mdds/flat_segment_tree.hpp> | ||||
75 | |||||
76 | using namespace ::com::sun::star; | ||||
77 | |||||
78 | namespace naturalsort { | ||||
79 | |||||
80 | using namespace ::com::sun::star::i18n; | ||||
81 | |||||
82 | /** Splits a given string into three parts: the prefix, number string, and | ||||
83 | the suffix. | ||||
84 | |||||
85 | @param sWhole | ||||
86 | Original string to be split into pieces | ||||
87 | |||||
88 | @param sPrefix | ||||
89 | Prefix string that consists of the part before the first number token. | ||||
90 | If no number was found, sPrefix is unchanged. | ||||
91 | |||||
92 | @param sSuffix | ||||
93 | String after the last number token. This may still contain number strings. | ||||
94 | If no number was found, sSuffix is unchanged. | ||||
95 | |||||
96 | @param fNum | ||||
97 | Number converted from the middle number string | ||||
98 | If no number was found, fNum is unchanged. | ||||
99 | |||||
100 | @return Returns TRUE if a numeral element is found in a given string, or | ||||
101 | FALSE if no numeral element is found. | ||||
102 | */ | ||||
103 | static bool SplitString( const OUString &sWhole, | ||||
104 | OUString &sPrefix, OUString &sSuffix, double &fNum ) | ||||
105 | { | ||||
106 | // Get prefix element, search for any digit and stop. | ||||
107 | sal_Int32 nPos = 0; | ||||
108 | while (nPos < sWhole.getLength()) | ||||
109 | { | ||||
110 | const sal_uInt16 nType = ScGlobal::getCharClassPtr()->getCharacterType( sWhole, nPos); | ||||
111 | if (nType & KCharacterType::DIGIT) | ||||
112 | break; | ||||
113 | sWhole.iterateCodePoints( &nPos ); | ||||
114 | } | ||||
115 | |||||
116 | // Return FALSE if no numeral element is found | ||||
117 | if ( nPos == sWhole.getLength() ) | ||||
118 | return false; | ||||
119 | |||||
120 | // Get numeral element | ||||
121 | const OUString& sUser = ScGlobal::getLocaleDataPtr()->getNumDecimalSep(); | ||||
122 | ParseResult aPRNum = ScGlobal::getCharClassPtr()->parsePredefinedToken( | ||||
123 | KParseType::ANY_NUMBER, sWhole, nPos, | ||||
124 | KParseTokens::ANY_NUMBER, "", KParseTokens::ANY_NUMBER, sUser ); | ||||
125 | |||||
126 | if ( aPRNum.EndPos == nPos ) | ||||
127 | { | ||||
128 | SAL_WARN("sc.core","naturalsort::SplitString - digit found but no number parsed, pos " <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sc.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||
129 | nPos << " : " << sWhole)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sc.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "naturalsort::SplitString - digit found but no number parsed, pos " << nPos << " : " << sWhole; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc.core"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "129" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
130 | return false; | ||||
131 | } | ||||
132 | |||||
133 | sPrefix = sWhole.copy( 0, nPos ); | ||||
134 | fNum = aPRNum.Value; | ||||
135 | sSuffix = sWhole.copy( aPRNum.EndPos ); | ||||
136 | |||||
137 | return true; | ||||
138 | } | ||||
139 | |||||
140 | /** Naturally compares two given strings. | ||||
141 | |||||
142 | This is the main function that should be called externally. It returns | ||||
143 | either 1, 0, or -1 depending on the comparison result of given two strings. | ||||
144 | |||||
145 | @param sInput1 | ||||
146 | Input string 1 | ||||
147 | |||||
148 | @param sInput2 | ||||
149 | Input string 2 | ||||
150 | |||||
151 | @param bCaseSens | ||||
152 | Boolean value for case sensitivity | ||||
153 | |||||
154 | @param pData | ||||
155 | Pointer to user defined sort list | ||||
156 | |||||
157 | @param pCW | ||||
158 | Pointer to collator wrapper for normal string comparison | ||||
159 | |||||
160 | @return Returns 1 if sInput1 is greater, 0 if sInput1 == sInput2, and -1 if | ||||
161 | sInput2 is greater. | ||||
162 | */ | ||||
163 | static short Compare( const OUString &sInput1, const OUString &sInput2, | ||||
164 | const bool bCaseSens, const ScUserListData* pData, const CollatorWrapper *pCW ) | ||||
165 | { | ||||
166 | OUString sStr1( sInput1 ), sStr2( sInput2 ), sPre1, sSuf1, sPre2, sSuf2; | ||||
167 | |||||
168 | do | ||||
169 | { | ||||
170 | double nNum1, nNum2; | ||||
171 | bool bNumFound1 = SplitString( sStr1, sPre1, sSuf1, nNum1 ); | ||||
172 | bool bNumFound2 = SplitString( sStr2, sPre2, sSuf2, nNum2 ); | ||||
173 | |||||
174 | short nPreRes; // Prefix comparison result | ||||
175 | if ( pData ) | ||||
176 | { | ||||
177 | if ( bCaseSens ) | ||||
178 | { | ||||
179 | if ( !bNumFound1 || !bNumFound2 ) | ||||
180 | return static_cast<short>(pData->Compare( sStr1, sStr2 )); | ||||
181 | else | ||||
182 | nPreRes = pData->Compare( sPre1, sPre2 ); | ||||
183 | } | ||||
184 | else | ||||
185 | { | ||||
186 | if ( !bNumFound1 || !bNumFound2 ) | ||||
187 | return static_cast<short>(pData->ICompare( sStr1, sStr2 )); | ||||
188 | else | ||||
189 | nPreRes = pData->ICompare( sPre1, sPre2 ); | ||||
190 | } | ||||
191 | } | ||||
192 | else | ||||
193 | { | ||||
194 | if ( !bNumFound1 || !bNumFound2 ) | ||||
195 | return static_cast<short>(pCW->compareString( sStr1, sStr2 )); | ||||
196 | else | ||||
197 | nPreRes = static_cast<short>(pCW->compareString( sPre1, sPre2 )); | ||||
198 | } | ||||
199 | |||||
200 | // Prefix strings differ. Return immediately. | ||||
201 | if ( nPreRes != 0 ) return nPreRes; | ||||
202 | |||||
203 | if ( nNum1 != nNum2 ) | ||||
204 | { | ||||
205 | if ( nNum1 < nNum2 ) return -1; | ||||
206 | return (nNum1 > nNum2) ? 1 : 0; | ||||
207 | } | ||||
208 | |||||
209 | // The prefix and the first numerical elements are equal, but the suffix | ||||
210 | // strings may still differ. Stay in the loop. | ||||
211 | |||||
212 | sStr1 = sSuf1; | ||||
213 | sStr2 = sSuf2; | ||||
214 | |||||
215 | } while (true); | ||||
216 | |||||
217 | return 0; | ||||
218 | } | ||||
219 | |||||
220 | } | ||||
221 | |||||
222 | namespace { | ||||
223 | |||||
224 | struct ScSortInfo final | ||||
225 | { | ||||
226 | ScRefCellValue maCell; | ||||
227 | SCCOLROW nOrg; | ||||
228 | }; | ||||
229 | |||||
230 | } | ||||
231 | |||||
232 | class ScSortInfoArray | ||||
233 | { | ||||
234 | public: | ||||
235 | |||||
236 | struct Cell | ||||
237 | { | ||||
238 | ScRefCellValue maCell; | ||||
239 | const sc::CellTextAttr* mpAttr; | ||||
240 | const ScPostIt* mpNote; | ||||
241 | std::vector<SdrObject*> maDrawObjects; | ||||
242 | const ScPatternAttr* mpPattern; | ||||
243 | |||||
244 | Cell() : mpAttr(nullptr), mpNote(nullptr), maDrawObjects(), mpPattern(nullptr) {} | ||||
245 | }; | ||||
246 | |||||
247 | struct Row | ||||
248 | { | ||||
249 | std::vector<Cell> maCells; | ||||
250 | |||||
251 | bool mbHidden:1; | ||||
252 | bool mbFiltered:1; | ||||
253 | |||||
254 | explicit Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {} | ||||
255 | }; | ||||
256 | |||||
257 | typedef std::vector<Row> RowsType; | ||||
258 | |||||
259 | private: | ||||
260 | std::unique_ptr<RowsType> mpRows; /// row-wise data table for sort by row operation. | ||||
261 | |||||
262 | std::vector<std::unique_ptr<ScSortInfo[]>> mvppInfo; | ||||
263 | SCCOLROW nStart; | ||||
264 | SCCOLROW mnLastIndex; /// index of last non-empty cell position. | ||||
265 | |||||
266 | std::vector<SCCOLROW> maOrderIndices; | ||||
267 | bool mbKeepQuery; | ||||
268 | bool mbUpdateRefs; | ||||
269 | |||||
270 | public: | ||||
271 | ScSortInfoArray(const ScSortInfoArray&) = delete; | ||||
272 | const ScSortInfoArray& operator=(const ScSortInfoArray&) = delete; | ||||
273 | |||||
274 | ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) : | ||||
275 | mvppInfo(nSorts), | ||||
276 | nStart( nInd1 ), | ||||
277 | mnLastIndex(nInd2), | ||||
278 | mbKeepQuery(false), | ||||
279 | mbUpdateRefs(false) | ||||
280 | { | ||||
281 | SCSIZE nCount( nInd2 - nInd1 + 1 ); | ||||
282 | if (nSorts) | ||||
283 | { | ||||
284 | for ( sal_uInt16 nSort = 0; nSort < nSorts; nSort++ ) | ||||
285 | { | ||||
286 | mvppInfo[nSort].reset(new ScSortInfo[nCount]); | ||||
287 | } | ||||
288 | } | ||||
289 | |||||
290 | for (size_t i = 0; i < nCount; ++i) | ||||
291 | maOrderIndices.push_back(i+nStart); | ||||
292 | } | ||||
293 | |||||
294 | void SetKeepQuery( bool b ) { mbKeepQuery = b; } | ||||
295 | |||||
296 | bool IsKeepQuery() const { return mbKeepQuery; } | ||||
297 | |||||
298 | void SetUpdateRefs( bool b ) { mbUpdateRefs = b; } | ||||
299 | |||||
300 | bool IsUpdateRefs() const { return mbUpdateRefs; } | ||||
301 | |||||
302 | /** | ||||
303 | * Call this only during normal sorting, not from reordering. | ||||
304 | */ | ||||
305 | std::unique_ptr<ScSortInfo[]> const & GetFirstArray() const | ||||
306 | { | ||||
307 | return mvppInfo[0]; | ||||
308 | } | ||||
309 | |||||
310 | /** | ||||
311 | * Call this only during normal sorting, not from reordering. | ||||
312 | */ | ||||
313 | ScSortInfo & Get( sal_uInt16 nSort, SCCOLROW nInd ) | ||||
314 | { | ||||
315 | return mvppInfo[nSort][ nInd - nStart ]; | ||||
316 | } | ||||
317 | |||||
318 | /** | ||||
319 | * Call this only during normal sorting, not from reordering. | ||||
320 | */ | ||||
321 | void Swap( SCCOLROW nInd1, SCCOLROW nInd2 ) | ||||
322 | { | ||||
323 | if (nInd1 == nInd2) // avoid self-move-assign | ||||
324 | return; | ||||
325 | SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart); | ||||
326 | SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart); | ||||
327 | for ( sal_uInt16 nSort = 0; nSort < static_cast<sal_uInt16>(mvppInfo.size()); nSort++ ) | ||||
328 | { | ||||
329 | auto & ppInfo = mvppInfo[nSort]; | ||||
330 | std::swap(ppInfo[n1], ppInfo[n2]); | ||||
331 | } | ||||
332 | |||||
333 | std::swap(maOrderIndices[n1], maOrderIndices[n2]); | ||||
334 | |||||
335 | if (mpRows) | ||||
336 | { | ||||
337 | // Swap rows in data table. | ||||
338 | RowsType& rRows = *mpRows; | ||||
339 | std::swap(rRows[n1], rRows[n2]); | ||||
340 | } | ||||
341 | } | ||||
342 | |||||
343 | void SetOrderIndices( const std::vector<SCCOLROW>& rIndices ) | ||||
344 | { | ||||
345 | maOrderIndices = rIndices; | ||||
346 | } | ||||
347 | |||||
348 | /** | ||||
349 | * @param rIndices indices are actual row positions on the sheet, not an | ||||
350 | * offset from the top row. | ||||
351 | */ | ||||
352 | void ReorderByRow( const std::vector<SCCOLROW>& rIndices ) | ||||
353 | { | ||||
354 | if (!mpRows) | ||||
355 | return; | ||||
356 | |||||
357 | RowsType& rRows = *mpRows; | ||||
358 | |||||
359 | std::vector<SCCOLROW> aOrderIndices2; | ||||
360 | aOrderIndices2.reserve(rIndices.size()); | ||||
361 | |||||
362 | RowsType aRows2; | ||||
363 | aRows2.reserve(rRows.size()); | ||||
364 | |||||
365 | for (const auto& rIndex : rIndices) | ||||
366 | { | ||||
367 | size_t nPos = rIndex - nStart; // switch to an offset to top row. | ||||
368 | aRows2.push_back(rRows[nPos]); | ||||
369 | aOrderIndices2.push_back(maOrderIndices[nPos]); | ||||
370 | } | ||||
371 | |||||
372 | rRows.swap(aRows2); | ||||
373 | maOrderIndices.swap(aOrderIndices2); | ||||
374 | } | ||||
375 | |||||
376 | sal_uInt16 GetUsedSorts() const { return mvppInfo.size(); } | ||||
377 | |||||
378 | SCCOLROW GetStart() const { return nStart; } | ||||
379 | SCCOLROW GetLast() const { return mnLastIndex; } | ||||
380 | |||||
381 | const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; } | ||||
382 | |||||
383 | RowsType& InitDataRows( size_t nRowSize, size_t nColSize ) | ||||
384 | { | ||||
385 | mpRows.reset(new RowsType); | ||||
386 | mpRows->resize(nRowSize, Row(nColSize)); | ||||
387 | return *mpRows; | ||||
388 | } | ||||
389 | |||||
390 | RowsType* GetDataRows() | ||||
391 | { | ||||
392 | return mpRows.get(); | ||||
393 | } | ||||
394 | }; | ||||
395 | |||||
396 | namespace { | ||||
397 | |||||
398 | void initDataRows( | ||||
399 | ScSortInfoArray& rArray, ScTable& rTab, ScColContainer& rCols, | ||||
400 | SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, | ||||
401 | bool bPattern, bool bHiddenFiltered ) | ||||
402 | { | ||||
403 | // Fill row-wise data table. | ||||
404 | ScSortInfoArray::RowsType& rRows = rArray.InitDataRows(nRow2-nRow1+1, nCol2-nCol1+1); | ||||
405 | |||||
406 | for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) | ||||
407 | { | ||||
408 | ScColumn& rCol = rCols[nCol]; | ||||
409 | |||||
410 | // Skip reordering of cell formats if the whole span is on the same pattern entry. | ||||
411 | bool bUniformPattern = rCol.GetPatternCount(nRow1, nRow2) < 2u; | ||||
412 | |||||
413 | sc::ColumnBlockConstPosition aBlockPos; | ||||
414 | rCol.InitBlockPosition(aBlockPos); | ||||
415 | std::map<SCROW, std::vector<SdrObject*>> aRowDrawObjects; | ||||
416 | ScDrawLayer* pDrawLayer = rTab.GetDoc().GetDrawLayer(); | ||||
417 | if (pDrawLayer) | ||||
418 | aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRange(rTab.GetTab(), nCol, nRow1, nRow2); | ||||
419 | |||||
420 | for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) | ||||
421 | { | ||||
422 | ScSortInfoArray::Row& rRow = rRows[nRow-nRow1]; | ||||
423 | ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-nCol1]; | ||||
424 | rCell.maCell = rCol.GetCellValue(aBlockPos, nRow); | ||||
425 | rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow); | ||||
426 | rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow); | ||||
427 | if (pDrawLayer) | ||||
428 | rCell.maDrawObjects = aRowDrawObjects[nRow]; | ||||
429 | |||||
430 | if (!bUniformPattern && bPattern) | ||||
431 | rCell.mpPattern = rCol.GetPattern(nRow); | ||||
432 | } | ||||
433 | } | ||||
434 | |||||
435 | if (bHiddenFiltered) | ||||
436 | { | ||||
437 | for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) | ||||
438 | { | ||||
439 | ScSortInfoArray::Row& rRow = rRows[nRow-nRow1]; | ||||
440 | rRow.mbHidden = rTab.RowHidden(nRow); | ||||
441 | rRow.mbFiltered = rTab.RowFiltered(nRow); | ||||
442 | } | ||||
443 | } | ||||
444 | } | ||||
445 | |||||
446 | } | ||||
447 | |||||
448 | std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray( const sc::ReorderParam& rParam ) | ||||
449 | { | ||||
450 | std::unique_ptr<ScSortInfoArray> pArray; | ||||
451 | |||||
452 | if (rParam.mbByRow) | ||||
453 | { | ||||
454 | // Create a sort info array with just the data table. | ||||
455 | SCROW nRow1 = rParam.maSortRange.aStart.Row(); | ||||
456 | SCROW nRow2 = rParam.maSortRange.aEnd.Row(); | ||||
457 | SCCOL nCol1 = rParam.maSortRange.aStart.Col(); | ||||
458 | SCCOL nCol2 = rParam.maSortRange.aEnd.Col(); | ||||
459 | |||||
460 | pArray.reset(new ScSortInfoArray(0, nRow1, nRow2)); | ||||
461 | pArray->SetKeepQuery(rParam.mbHiddenFiltered); | ||||
462 | pArray->SetUpdateRefs(rParam.mbUpdateRefs); | ||||
463 | |||||
464 | initDataRows( | ||||
465 | *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2, | ||||
466 | rParam.mbPattern, rParam.mbHiddenFiltered); | ||||
467 | } | ||||
468 | else | ||||
469 | { | ||||
470 | SCCOLROW nCol1 = rParam.maSortRange.aStart.Col(); | ||||
471 | SCCOLROW nCol2 = rParam.maSortRange.aEnd.Col(); | ||||
472 | |||||
473 | pArray.reset(new ScSortInfoArray(0, nCol1, nCol2)); | ||||
474 | pArray->SetKeepQuery(rParam.mbHiddenFiltered); | ||||
475 | pArray->SetUpdateRefs(rParam.mbUpdateRefs); | ||||
476 | } | ||||
477 | |||||
478 | return pArray; | ||||
479 | } | ||||
480 | |||||
481 | std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray( | ||||
482 | const ScSortParam& rSortParam, SCCOLROW nInd1, SCCOLROW nInd2, | ||||
483 | bool bKeepQuery, bool bUpdateRefs ) | ||||
484 | { | ||||
485 | sal_uInt16 nUsedSorts = 1; | ||||
486 | while ( nUsedSorts < rSortParam.GetSortKeyCount() && rSortParam.maKeyState[nUsedSorts].bDoSort ) | ||||
487 | nUsedSorts++; | ||||
488 | std::unique_ptr<ScSortInfoArray> pArray(new ScSortInfoArray( nUsedSorts, nInd1, nInd2 )); | ||||
489 | pArray->SetKeepQuery(bKeepQuery); | ||||
490 | pArray->SetUpdateRefs(bUpdateRefs); | ||||
491 | |||||
492 | if ( rSortParam.bByRow ) | ||||
493 | { | ||||
494 | for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) | ||||
495 | { | ||||
496 | SCCOL nCol = static_cast<SCCOL>(rSortParam.maKeyState[nSort].nField); | ||||
497 | ScColumn* pCol = &aCol[nCol]; | ||||
498 | sc::ColumnBlockConstPosition aBlockPos; | ||||
499 | pCol->InitBlockPosition(aBlockPos); | ||||
500 | for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ ) | ||||
501 | { | ||||
502 | ScSortInfo & rInfo = pArray->Get( nSort, nRow ); | ||||
503 | rInfo.maCell = pCol->GetCellValue(aBlockPos, nRow); | ||||
504 | rInfo.nOrg = nRow; | ||||
505 | } | ||||
506 | } | ||||
507 | |||||
508 | initDataRows( | ||||
509 | *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2, | ||||
510 | rSortParam.bIncludePattern, bKeepQuery); | ||||
511 | } | ||||
512 | else | ||||
513 | { | ||||
514 | for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) | ||||
515 | { | ||||
516 | SCROW nRow = rSortParam.maKeyState[nSort].nField; | ||||
517 | for ( SCCOL nCol = static_cast<SCCOL>(nInd1); | ||||
518 | nCol <= static_cast<SCCOL>(nInd2); nCol++ ) | ||||
519 | { | ||||
520 | ScSortInfo & rInfo = pArray->Get( nSort, nCol ); | ||||
521 | rInfo.maCell = GetCellValue(nCol, nRow); | ||||
522 | rInfo.nOrg = nCol; | ||||
523 | } | ||||
524 | } | ||||
525 | } | ||||
526 | return pArray; | ||||
527 | } | ||||
528 | |||||
529 | namespace { | ||||
530 | |||||
531 | struct SortedColumn | ||||
532 | { | ||||
533 | typedef mdds::flat_segment_tree<SCROW, const ScPatternAttr*> PatRangeType; | ||||
534 | |||||
535 | sc::CellStoreType maCells; | ||||
536 | sc::CellTextAttrStoreType maCellTextAttrs; | ||||
537 | sc::BroadcasterStoreType maBroadcasters; | ||||
538 | sc::CellNoteStoreType maCellNotes; | ||||
539 | std::vector<std::vector<SdrObject*>> maCellDrawObjects; | ||||
540 | |||||
541 | PatRangeType maPatterns; | ||||
542 | PatRangeType::const_iterator miPatternPos; | ||||
543 | |||||
544 | SortedColumn(const SortedColumn&) = delete; | ||||
545 | const SortedColumn operator=(const SortedColumn&) = delete; | ||||
546 | |||||
547 | explicit SortedColumn( size_t nTopEmptyRows, const ScSheetLimits& rSheetLimits ) : | ||||
548 | maCells(nTopEmptyRows), | ||||
549 | maCellTextAttrs(nTopEmptyRows), | ||||
550 | maBroadcasters(nTopEmptyRows), | ||||
551 | maCellNotes(nTopEmptyRows), | ||||
552 | maCellDrawObjects(), | ||||
553 | maPatterns(0, rSheetLimits.GetMaxRowCount(), nullptr), | ||||
554 | miPatternPos(maPatterns.begin()) {} | ||||
555 | |||||
556 | void setPattern( SCROW nRow, const ScPatternAttr* pPat ) | ||||
557 | { | ||||
558 | miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, pPat).first; | ||||
559 | } | ||||
560 | }; | ||||
561 | |||||
562 | struct SortedRowFlags | ||||
563 | { | ||||
564 | typedef mdds::flat_segment_tree<SCROW,bool> FlagsType; | ||||
565 | |||||
566 | FlagsType maRowsHidden; | ||||
567 | FlagsType maRowsFiltered; | ||||
568 | FlagsType::const_iterator miPosHidden; | ||||
569 | FlagsType::const_iterator miPosFiltered; | ||||
570 | |||||
571 | SortedRowFlags(const ScSheetLimits& rSheetLimits) : | ||||
572 | maRowsHidden(0, rSheetLimits.GetMaxRowCount(), false), | ||||
573 | maRowsFiltered(0, rSheetLimits.GetMaxRowCount(), false), | ||||
574 | miPosHidden(maRowsHidden.begin()), | ||||
575 | miPosFiltered(maRowsFiltered.begin()) {} | ||||
576 | |||||
577 | void setRowHidden( SCROW nRow, bool b ) | ||||
578 | { | ||||
579 | miPosHidden = maRowsHidden.insert(miPosHidden, nRow, nRow+1, b).first; | ||||
580 | } | ||||
581 | |||||
582 | void setRowFiltered( SCROW nRow, bool b ) | ||||
583 | { | ||||
584 | miPosFiltered = maRowsFiltered.insert(miPosFiltered, nRow, nRow+1, b).first; | ||||
585 | } | ||||
586 | |||||
587 | void swap( SortedRowFlags& r ) | ||||
588 | { | ||||
589 | maRowsHidden.swap(r.maRowsHidden); | ||||
590 | maRowsFiltered.swap(r.maRowsFiltered); | ||||
591 | |||||
592 | // Just reset the position hints. | ||||
593 | miPosHidden = maRowsHidden.begin(); | ||||
594 | miPosFiltered = maRowsFiltered.begin(); | ||||
595 | } | ||||
596 | }; | ||||
597 | |||||
598 | struct PatternSpan | ||||
599 | { | ||||
600 | SCROW mnRow1; | ||||
601 | SCROW mnRow2; | ||||
602 | const ScPatternAttr* mpPattern; | ||||
603 | |||||
604 | PatternSpan( SCROW nRow1, SCROW nRow2, const ScPatternAttr* pPat ) : | ||||
605 | mnRow1(nRow1), mnRow2(nRow2), mpPattern(pPat) {} | ||||
606 | }; | ||||
607 | |||||
608 | } | ||||
609 | |||||
610 | bool ScTable::IsSortCollatorGlobal() const | ||||
611 | { | ||||
612 | return pSortCollator == ScGlobal::GetCollator() || | ||||
613 | pSortCollator == ScGlobal::GetCaseCollator(); | ||||
614 | } | ||||
615 | |||||
616 | void ScTable::InitSortCollator( const ScSortParam& rPar ) | ||||
617 | { | ||||
618 | if ( !rPar.aCollatorLocale.Language.isEmpty() ) | ||||
619 | { | ||||
620 | if ( !pSortCollator || IsSortCollatorGlobal() ) | ||||
621 | pSortCollator = new CollatorWrapper( comphelper::getProcessComponentContext() ); | ||||
622 | pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm, | ||||
623 | rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNOREScss::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE) ); | ||||
624 | } | ||||
625 | else | ||||
626 | { // SYSTEM | ||||
627 | DestroySortCollator(); | ||||
628 | pSortCollator = (rPar.bCaseSens ? ScGlobal::GetCaseCollator() : | ||||
629 | ScGlobal::GetCollator()); | ||||
630 | } | ||||
631 | } | ||||
632 | |||||
633 | void ScTable::DestroySortCollator() | ||||
634 | { | ||||
635 | if ( pSortCollator ) | ||||
636 | { | ||||
637 | if ( !IsSortCollatorGlobal() ) | ||||
638 | delete pSortCollator; | ||||
639 | pSortCollator = nullptr; | ||||
640 | } | ||||
641 | } | ||||
642 | |||||
643 | namespace { | ||||
644 | |||||
645 | template<typename Hint, typename ReorderMap, typename Index> | ||||
646 | class ReorderNotifier | ||||
647 | { | ||||
648 | Hint maHint; | ||||
649 | public: | ||||
650 | ReorderNotifier( const ReorderMap& rMap, SCTAB nTab, Index nPos1, Index nPos2 ) : | ||||
651 | maHint(rMap, nTab, nPos1, nPos2) {} | ||||
652 | |||||
653 | void operator() ( SvtListener* p ) | ||||
654 | { | ||||
655 | p->Notify(maHint); | ||||
656 | } | ||||
657 | }; | ||||
658 | |||||
659 | class FormulaGroupPosCollector | ||||
660 | { | ||||
661 | sc::RefQueryFormulaGroup& mrQuery; | ||||
662 | |||||
663 | public: | ||||
664 | explicit FormulaGroupPosCollector( sc::RefQueryFormulaGroup& rQuery ) : mrQuery(rQuery) {} | ||||
665 | |||||
666 | void operator() ( const SvtListener* p ) | ||||
667 | { | ||||
668 | p->Query(mrQuery); | ||||
669 | } | ||||
670 | }; | ||||
671 | |||||
672 | void fillSortedColumnArray( | ||||
673 | std::vector<std::unique_ptr<SortedColumn>>& rSortedCols, | ||||
674 | SortedRowFlags& rRowFlags, | ||||
675 | std::vector<SvtListener*>& rCellListeners, | ||||
676 | ScSortInfoArray* pArray, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress, const ScTable* pTable ) | ||||
677 | { | ||||
678 | SCROW nRow1 = pArray->GetStart(); | ||||
679 | ScSortInfoArray::RowsType* pRows = pArray->GetDataRows(); | ||||
680 | std::vector<SCCOLROW> aOrderIndices = pArray->GetOrderIndices(); | ||||
681 | |||||
682 | size_t nColCount = nCol2 - nCol1 + 1; | ||||
683 | std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells. | ||||
684 | SortedRowFlags aRowFlags(pTable->GetDoc().GetSheetLimits()); | ||||
685 | aSortedCols.reserve(nColCount); | ||||
686 | for (size_t i = 0; i < nColCount; ++i) | ||||
687 | { | ||||
688 | // In the sorted column container, element positions and row | ||||
689 | // positions must match, else formula cells may mis-behave during | ||||
690 | // grouping. | ||||
691 | aSortedCols.push_back(std::make_unique<SortedColumn>(nRow1, pTable->GetDoc().GetSheetLimits())); | ||||
692 | } | ||||
693 | |||||
694 | for (size_t i = 0; i < pRows->size(); ++i) | ||||
695 | { | ||||
696 | ScSortInfoArray::Row& rRow = (*pRows)[i]; | ||||
697 | for (size_t j = 0; j < rRow.maCells.size(); ++j) | ||||
698 | { | ||||
699 | ScAddress aCellPos(nCol1 + j, nRow1 + i, nTab); | ||||
700 | |||||
701 | ScSortInfoArray::Cell& rCell = rRow.maCells[j]; | ||||
702 | |||||
703 | sc::CellStoreType& rCellStore = aSortedCols.at(j)->maCells; | ||||
704 | switch (rCell.maCell.meType) | ||||
705 | { | ||||
706 | case CELLTYPE_STRING: | ||||
707 | assert(rCell.mpAttr)(static_cast <bool> (rCell.mpAttr) ? void (0) : __assert_fail ("rCell.mpAttr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 707, __extension__ __PRETTY_FUNCTION__)); | ||||
708 | rCellStore.push_back(*rCell.maCell.mpString); | ||||
709 | break; | ||||
710 | case CELLTYPE_VALUE: | ||||
711 | assert(rCell.mpAttr)(static_cast <bool> (rCell.mpAttr) ? void (0) : __assert_fail ("rCell.mpAttr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 711, __extension__ __PRETTY_FUNCTION__)); | ||||
712 | rCellStore.push_back(rCell.maCell.mfValue); | ||||
713 | break; | ||||
714 | case CELLTYPE_EDIT: | ||||
715 | assert(rCell.mpAttr)(static_cast <bool> (rCell.mpAttr) ? void (0) : __assert_fail ("rCell.mpAttr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 715, __extension__ __PRETTY_FUNCTION__)); | ||||
716 | rCellStore.push_back(rCell.maCell.mpEditText->Clone().release()); | ||||
717 | break; | ||||
718 | case CELLTYPE_FORMULA: | ||||
719 | { | ||||
720 | assert(rCell.mpAttr)(static_cast <bool> (rCell.mpAttr) ? void (0) : __assert_fail ("rCell.mpAttr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 720, __extension__ __PRETTY_FUNCTION__)); | ||||
721 | ScAddress aOldPos = rCell.maCell.mpFormula->aPos; | ||||
722 | |||||
723 | ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos ); | ||||
724 | if (pArray->IsUpdateRefs()) | ||||
725 | { | ||||
726 | pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula); | ||||
727 | pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos); | ||||
728 | } | ||||
729 | else | ||||
730 | { | ||||
731 | pNew->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, aCellPos); | ||||
732 | } | ||||
733 | |||||
734 | if (!rCellListeners.empty()) | ||||
735 | { | ||||
736 | // Original source cells will be deleted during | ||||
737 | // sc::CellStoreType::transfer(), SvtListener is a base | ||||
738 | // class, so we need to replace it. | ||||
739 | auto it( ::std::find( rCellListeners.begin(), rCellListeners.end(), rCell.maCell.mpFormula)); | ||||
740 | if (it != rCellListeners.end()) | ||||
741 | *it = pNew; | ||||
742 | } | ||||
743 | |||||
744 | rCellStore.push_back(pNew); | ||||
745 | } | ||||
746 | break; | ||||
747 | default: | ||||
748 | //assert(!rCell.mpAttr); | ||||
749 | // This assert doesn't hold, for example | ||||
750 | // CopyCellsFromClipHandler may omit copying cells during | ||||
751 | // PasteSpecial for which CopyTextAttrsFromClipHandler | ||||
752 | // still copies a CellTextAttr. So if that really is not | ||||
753 | // expected then fix it there. | ||||
754 | rCellStore.push_back_empty(); | ||||
755 | } | ||||
756 | |||||
757 | sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j)->maCellTextAttrs; | ||||
758 | if (rCell.mpAttr) | ||||
759 | rAttrStore.push_back(*rCell.mpAttr); | ||||
760 | else | ||||
761 | rAttrStore.push_back_empty(); | ||||
762 | |||||
763 | if (pArray->IsUpdateRefs()) | ||||
764 | { | ||||
765 | // At this point each broadcaster instance is managed by 2 | ||||
766 | // containers. We will release those in the original storage | ||||
767 | // below before transferring them to the document. | ||||
768 | const SvtBroadcaster* pBroadcaster = pTable->GetBroadcaster( nCol1 + j, aOrderIndices[i]); | ||||
769 | sc::BroadcasterStoreType& rBCStore = aSortedCols.at(j)->maBroadcasters; | ||||
770 | if (pBroadcaster) | ||||
771 | // A const pointer would be implicitly converted to a bool type. | ||||
772 | rBCStore.push_back(const_cast<SvtBroadcaster*>(pBroadcaster)); | ||||
773 | else | ||||
774 | rBCStore.push_back_empty(); | ||||
775 | } | ||||
776 | |||||
777 | // The same with cell note instances ... | ||||
778 | sc::CellNoteStoreType& rNoteStore = aSortedCols.at(j)->maCellNotes; | ||||
779 | if (rCell.mpNote) | ||||
780 | rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote)); | ||||
781 | else | ||||
782 | rNoteStore.push_back_empty(); | ||||
783 | |||||
784 | // Add cell anchored images | ||||
785 | aSortedCols.at(j)->maCellDrawObjects.push_back(rCell.maDrawObjects); | ||||
786 | |||||
787 | if (rCell.mpPattern) | ||||
788 | aSortedCols.at(j)->setPattern(aCellPos.Row(), rCell.mpPattern); | ||||
789 | } | ||||
790 | |||||
791 | if (pArray->IsKeepQuery()) | ||||
792 | { | ||||
793 | // Hidden and filtered flags are first converted to segments. | ||||
794 | SCROW nRow = nRow1 + i; | ||||
795 | aRowFlags.setRowHidden(nRow, rRow.mbHidden); | ||||
796 | aRowFlags.setRowFiltered(nRow, rRow.mbFiltered); | ||||
797 | } | ||||
798 | |||||
799 | if (pProgress) | ||||
800 | pProgress->SetStateOnPercent(i); | ||||
801 | } | ||||
802 | |||||
803 | rSortedCols.swap(aSortedCols); | ||||
804 | rRowFlags.swap(aRowFlags); | ||||
805 | } | ||||
806 | |||||
807 | void expandRowRange( ScRange& rRange, SCROW nTop, SCROW nBottom ) | ||||
808 | { | ||||
809 | if (nTop < rRange.aStart.Row()) | ||||
810 | rRange.aStart.SetRow(nTop); | ||||
811 | |||||
812 | if (rRange.aEnd.Row() < nBottom) | ||||
813 | rRange.aEnd.SetRow(nBottom); | ||||
814 | } | ||||
815 | |||||
816 | class FormulaCellCollectAction : public sc::ColumnSpanSet::ColumnAction | ||||
817 | { | ||||
818 | std::vector<ScFormulaCell*>& mrCells; | ||||
819 | ScColumn* mpCol; | ||||
820 | |||||
821 | public: | ||||
822 | explicit FormulaCellCollectAction( std::vector<ScFormulaCell*>& rCells ) : | ||||
823 | mrCells(rCells), mpCol(nullptr) {} | ||||
824 | |||||
825 | virtual void startColumn( ScColumn* pCol ) override | ||||
826 | { | ||||
827 | mpCol = pCol; | ||||
828 | } | ||||
829 | |||||
830 | virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override | ||||
831 | { | ||||
832 | assert(mpCol)(static_cast <bool> (mpCol) ? void (0) : __assert_fail ( "mpCol", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 832, __extension__ __PRETTY_FUNCTION__)); | ||||
833 | |||||
834 | if (!bVal) | ||||
835 | return; | ||||
836 | |||||
837 | mpCol->CollectFormulaCells(mrCells, nRow1, nRow2); | ||||
838 | } | ||||
839 | }; | ||||
840 | |||||
841 | class ListenerStartAction : public sc::ColumnSpanSet::ColumnAction | ||||
842 | { | ||||
843 | ScColumn* mpCol; | ||||
844 | |||||
845 | std::shared_ptr<sc::ColumnBlockPositionSet> mpPosSet; | ||||
846 | sc::StartListeningContext maStartCxt; | ||||
847 | sc::EndListeningContext maEndCxt; | ||||
848 | |||||
849 | public: | ||||
850 | explicit ListenerStartAction( ScDocument& rDoc ) : | ||||
851 | mpCol(nullptr), | ||||
852 | mpPosSet(std::make_shared<sc::ColumnBlockPositionSet>(rDoc)), | ||||
853 | maStartCxt(rDoc, mpPosSet), | ||||
854 | maEndCxt(rDoc, mpPosSet) {} | ||||
855 | |||||
856 | virtual void startColumn( ScColumn* pCol ) override | ||||
857 | { | ||||
858 | mpCol = pCol; | ||||
859 | } | ||||
860 | |||||
861 | virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override | ||||
862 | { | ||||
863 | assert(mpCol)(static_cast <bool> (mpCol) ? void (0) : __assert_fail ( "mpCol", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 863, __extension__ __PRETTY_FUNCTION__)); | ||||
864 | |||||
865 | if (!bVal) | ||||
866 | return; | ||||
867 | |||||
868 | mpCol->StartListeningFormulaCells(maStartCxt, maEndCxt, nRow1, nRow2); | ||||
869 | } | ||||
870 | }; | ||||
871 | |||||
872 | } | ||||
873 | |||||
874 | void ScTable::SortReorderByColumn( | ||||
875 | const ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress ) | ||||
876 | { | ||||
877 | SCCOLROW nStart = pArray->GetStart(); | ||||
878 | SCCOLROW nLast = pArray->GetLast(); | ||||
879 | |||||
880 | std::vector<SCCOLROW> aIndices = pArray->GetOrderIndices(); | ||||
881 | size_t nCount = aIndices.size(); | ||||
882 | |||||
883 | // Cut formula grouping at row and reference boundaries before the reordering. | ||||
884 | ScRange aSortRange(nStart, nRow1, nTab, nLast, nRow2, nTab); | ||||
885 | for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol) | ||||
886 | aCol[nCol].SplitFormulaGroupByRelativeRef(aSortRange); | ||||
887 | |||||
888 | // Collect all listeners of cell broadcasters of sorted range. | ||||
889 | std::vector<SvtListener*> aCellListeners; | ||||
890 | |||||
891 | if (!pArray->IsUpdateRefs()) | ||||
892 | { | ||||
893 | // Collect listeners of cell broadcasters. | ||||
894 | for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol) | ||||
895 | aCol[nCol].CollectListeners(aCellListeners, nRow1, nRow2); | ||||
896 | |||||
897 | // Remove any duplicate listener entries. We must ensure that we | ||||
898 | // notify each unique listener only once. | ||||
899 | std::sort(aCellListeners.begin(), aCellListeners.end()); | ||||
900 | aCellListeners.erase(std::unique(aCellListeners.begin(), aCellListeners.end()), aCellListeners.end()); | ||||
901 | |||||
902 | // Notify the cells' listeners to stop listening. | ||||
903 | /* TODO: for performance this could be enhanced to stop and later | ||||
904 | * restart only listening to within the reordered range and keep | ||||
905 | * listening to everything outside untouched. */ | ||||
906 | sc::RefStopListeningHint aHint; | ||||
907 | for (auto const & l : aCellListeners) | ||||
908 | l->Notify(aHint); | ||||
909 | } | ||||
910 | |||||
911 | // table to keep track of column index to position in the index table. | ||||
912 | std::vector<SCCOLROW> aPosTable(nCount); | ||||
913 | for (size_t i = 0; i < nCount; ++i) | ||||
914 | aPosTable[aIndices[i]-nStart] = i; | ||||
915 | |||||
916 | SCCOLROW nDest = nStart; | ||||
917 | for (size_t i = 0; i < nCount; ++i, ++nDest) | ||||
918 | { | ||||
919 | SCCOLROW nSrc = aIndices[i]; | ||||
920 | if (nDest != nSrc) | ||||
921 | { | ||||
922 | aCol[nDest].Swap(aCol[nSrc], nRow1, nRow2, bPattern); | ||||
923 | |||||
924 | // Update the position of the index that was originally equal to nDest. | ||||
925 | size_t nPos = aPosTable[nDest-nStart]; | ||||
926 | aIndices[nPos] = nSrc; | ||||
927 | aPosTable[nSrc-nStart] = nPos; | ||||
928 | } | ||||
929 | |||||
930 | if (pProgress) | ||||
931 | pProgress->SetStateOnPercent(i); | ||||
932 | } | ||||
933 | |||||
934 | // Reset formula cell positions which became out-of-sync after column reordering. | ||||
935 | bool bUpdateRefs = pArray->IsUpdateRefs(); | ||||
936 | for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol) | ||||
937 | aCol[nCol].ResetFormulaCellPositions(nRow1, nRow2, bUpdateRefs); | ||||
938 | |||||
939 | if (pArray->IsUpdateRefs()) | ||||
940 | { | ||||
941 | // Set up column reorder map (for later broadcasting of reference updates). | ||||
942 | sc::ColRowReorderMapType aColMap; | ||||
943 | const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices(); | ||||
944 | for (size_t i = 0, n = rOldIndices.size(); i < n; ++i) | ||||
945 | { | ||||
946 | SCCOL nNew = i + nStart; | ||||
947 | SCCOL nOld = rOldIndices[i]; | ||||
948 | aColMap.emplace(nOld, nNew); | ||||
949 | } | ||||
950 | |||||
951 | // Collect all listeners within sorted range ahead of time. | ||||
952 | std::vector<SvtListener*> aListeners; | ||||
953 | |||||
954 | for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol) | ||||
955 | aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); | ||||
956 | |||||
957 | // Get all area listeners that listen on one column within the range | ||||
958 | // and end their listening. | ||||
959 | ScRange aMoveRange( nStart, nRow1, nTab, nLast, nRow2, nTab); | ||||
960 | std::vector<sc::AreaListener> aAreaListeners = rDocument.GetBASM()->GetAllListeners( | ||||
961 | aMoveRange, sc::AreaOverlapType::OneColumnInside); | ||||
962 | { | ||||
963 | for (auto& rAreaListener : aAreaListeners) | ||||
964 | { | ||||
965 | rDocument.EndListeningArea(rAreaListener.maArea, rAreaListener.mbGroupListening, rAreaListener.mpListener); | ||||
966 | aListeners.push_back( rAreaListener.mpListener); | ||||
967 | } | ||||
968 | } | ||||
969 | |||||
970 | // Remove any duplicate listener entries and notify all listeners | ||||
971 | // afterward. We must ensure that we notify each unique listener only | ||||
972 | // once. | ||||
973 | std::sort(aListeners.begin(), aListeners.end()); | ||||
974 | aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end()); | ||||
975 | ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> aFunc(aColMap, nTab, nRow1, nRow2); | ||||
976 | std::for_each(aListeners.begin(), aListeners.end(), aFunc); | ||||
977 | |||||
978 | // Re-start area listeners on the reordered columns. | ||||
979 | { | ||||
980 | for (auto& rAreaListener : aAreaListeners) | ||||
981 | { | ||||
982 | ScRange aNewRange = rAreaListener.maArea; | ||||
983 | sc::ColRowReorderMapType::const_iterator itCol = aColMap.find( aNewRange.aStart.Col()); | ||||
984 | if (itCol != aColMap.end()) | ||||
985 | { | ||||
986 | aNewRange.aStart.SetCol( itCol->second); | ||||
987 | aNewRange.aEnd.SetCol( itCol->second); | ||||
988 | } | ||||
989 | rDocument.StartListeningArea(aNewRange, rAreaListener.mbGroupListening, rAreaListener.mpListener); | ||||
990 | } | ||||
991 | } | ||||
992 | } | ||||
993 | else // !(pArray->IsUpdateRefs()) | ||||
994 | { | ||||
995 | // Notify the cells' listeners to (re-)start listening. | ||||
996 | sc::RefStartListeningHint aHint; | ||||
997 | for (auto const & l : aCellListeners) | ||||
998 | l->Notify(aHint); | ||||
999 | } | ||||
1000 | |||||
1001 | // Re-join formulas at row boundaries now that all the references have | ||||
1002 | // been adjusted for column reordering. | ||||
1003 | for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol) | ||||
1004 | { | ||||
1005 | sc::CellStoreType& rCells = aCol[nCol].maCells; | ||||
1006 | sc::CellStoreType::position_type aPos = rCells.position(nRow1); | ||||
1007 | sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); | ||||
1008 | if (nRow2 < rDocument.MaxRow()) | ||||
1009 | { | ||||
1010 | aPos = rCells.position(aPos.first, nRow2+1); | ||||
1011 | sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); | ||||
1012 | } | ||||
1013 | } | ||||
1014 | } | ||||
1015 | |||||
1016 | void ScTable::SortReorderByRow( | ||||
1017 | ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress ) | ||||
1018 | { | ||||
1019 | assert(!pArray->IsUpdateRefs())(static_cast <bool> (!pArray->IsUpdateRefs()) ? void (0) : __assert_fail ("!pArray->IsUpdateRefs()", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 1019, __extension__ __PRETTY_FUNCTION__)); | ||||
1020 | |||||
1021 | if (nCol2 < nCol1) | ||||
1022 | return; | ||||
1023 | |||||
1024 | SCROW nRow1 = pArray->GetStart(); | ||||
1025 | SCROW nRow2 = pArray->GetLast(); | ||||
1026 | |||||
1027 | // Collect all listeners of cell broadcasters of sorted range. | ||||
1028 | std::vector<SvtListener*> aCellListeners; | ||||
1029 | |||||
1030 | // When the update ref mode is disabled, we need to detach all formula | ||||
1031 | // cells in the sorted range before reordering, and re-start them | ||||
1032 | // afterward. | ||||
1033 | { | ||||
1034 | sc::EndListeningContext aCxt(rDocument); | ||||
1035 | DetachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2); | ||||
1036 | } | ||||
1037 | |||||
1038 | // Collect listeners of cell broadcasters. | ||||
1039 | for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) | ||||
1040 | aCol[nCol].CollectListeners(aCellListeners, nRow1, nRow2); | ||||
1041 | |||||
1042 | // Remove any duplicate listener entries. We must ensure that we notify | ||||
1043 | // each unique listener only once. | ||||
1044 | std::sort(aCellListeners.begin(), aCellListeners.end()); | ||||
1045 | aCellListeners.erase(std::unique(aCellListeners.begin(), aCellListeners.end()), aCellListeners.end()); | ||||
1046 | |||||
1047 | // Notify the cells' listeners to stop listening. | ||||
1048 | /* TODO: for performance this could be enhanced to stop and later | ||||
1049 | * restart only listening to within the reordered range and keep | ||||
1050 | * listening to everything outside untouched. */ | ||||
1051 | { | ||||
1052 | sc::RefStopListeningHint aHint; | ||||
1053 | for (auto const & l : aCellListeners) | ||||
1054 | l->Notify(aHint); | ||||
1055 | } | ||||
1056 | |||||
1057 | // Split formula groups at the sort range boundaries (if applicable). | ||||
1058 | std::vector<SCROW> aRowBounds; | ||||
1059 | aRowBounds.reserve(2); | ||||
1060 | aRowBounds.push_back(nRow1); | ||||
1061 | aRowBounds.push_back(nRow2+1); | ||||
1062 | for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) | ||||
1063 | SplitFormulaGroups(nCol, aRowBounds); | ||||
1064 | |||||
1065 | // Cells in the data rows only reference values in the document. Make | ||||
1066 | // a copy before updating the document. | ||||
1067 | std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells. | ||||
1068 | SortedRowFlags aRowFlags(GetDoc().GetSheetLimits()); | ||||
1069 | fillSortedColumnArray(aSortedCols, aRowFlags, aCellListeners, pArray, nTab, nCol1, nCol2, pProgress, this); | ||||
1070 | |||||
1071 | for (size_t i = 0, n = aSortedCols.size(); i < n; ++i) | ||||
1072 | { | ||||
1073 | SCCOL nThisCol = i + nCol1; | ||||
1074 | |||||
1075 | { | ||||
1076 | sc::CellStoreType& rDest = aCol[nThisCol].maCells; | ||||
1077 | sc::CellStoreType& rSrc = aSortedCols[i]->maCells; | ||||
1078 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1079 | } | ||||
1080 | |||||
1081 | { | ||||
1082 | sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs; | ||||
1083 | sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs; | ||||
1084 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1085 | } | ||||
1086 | |||||
1087 | { | ||||
1088 | sc::CellNoteStoreType& rSrc = aSortedCols[i]->maCellNotes; | ||||
1089 | sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes; | ||||
1090 | |||||
1091 | // Do the same as broadcaster storage transfer (to prevent double deletion). | ||||
1092 | rDest.release_range(nRow1, nRow2); | ||||
1093 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1094 | aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2); | ||||
1095 | } | ||||
1096 | |||||
1097 | // Update draw object positions | ||||
1098 | aCol[nThisCol].UpdateDrawObjects(aSortedCols[i]->maCellDrawObjects, nRow1, nRow2); | ||||
1099 | |||||
1100 | { | ||||
1101 | // Get all row spans where the pattern is not NULL. | ||||
1102 | std::vector<PatternSpan> aSpans = | ||||
1103 | sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>( | ||||
1104 | aSortedCols[i]->maPatterns); | ||||
1105 | |||||
1106 | for (const auto& rSpan : aSpans) | ||||
1107 | { | ||||
1108 | assert(rSpan.mpPattern)(static_cast <bool> (rSpan.mpPattern) ? void (0) : __assert_fail ("rSpan.mpPattern", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 1108, __extension__ __PRETTY_FUNCTION__)); // should never be NULL. | ||||
1109 | rDocument.GetPool()->Put(*rSpan.mpPattern); | ||||
1110 | } | ||||
1111 | |||||
1112 | for (const auto& rSpan : aSpans) | ||||
1113 | { | ||||
1114 | aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern); | ||||
1115 | rDocument.GetPool()->Remove(*rSpan.mpPattern); | ||||
1116 | } | ||||
1117 | } | ||||
1118 | |||||
1119 | aCol[nThisCol].CellStorageModified(); | ||||
1120 | } | ||||
1121 | |||||
1122 | if (pArray->IsKeepQuery()) | ||||
1123 | { | ||||
1124 | aRowFlags.maRowsHidden.build_tree(); | ||||
1125 | aRowFlags.maRowsFiltered.build_tree(); | ||||
1126 | |||||
1127 | // Remove all flags in the range first. | ||||
1128 | SetRowHidden(nRow1, nRow2, false); | ||||
1129 | SetRowFiltered(nRow1, nRow2, false); | ||||
1130 | |||||
1131 | std::vector<sc::RowSpan> aSpans = | ||||
1132 | sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1); | ||||
1133 | |||||
1134 | for (const auto& rSpan : aSpans) | ||||
1135 | SetRowHidden(rSpan.mnRow1, rSpan.mnRow2, true); | ||||
1136 | |||||
1137 | aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1); | ||||
1138 | |||||
1139 | for (const auto& rSpan : aSpans) | ||||
1140 | SetRowFiltered(rSpan.mnRow1, rSpan.mnRow2, true); | ||||
1141 | } | ||||
1142 | |||||
1143 | // Notify the cells' listeners to (re-)start listening. | ||||
1144 | { | ||||
1145 | sc::RefStartListeningHint aHint; | ||||
1146 | for (auto const & l : aCellListeners) | ||||
1147 | l->Notify(aHint); | ||||
1148 | } | ||||
1149 | |||||
1150 | // Re-group columns in the sorted range too. | ||||
1151 | for (SCCOL i = nCol1; i <= nCol2; ++i) | ||||
1152 | aCol[i].RegroupFormulaCells(); | ||||
1153 | |||||
1154 | { | ||||
1155 | sc::StartListeningContext aCxt(rDocument); | ||||
1156 | AttachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2); | ||||
1157 | } | ||||
1158 | } | ||||
1159 | |||||
1160 | void ScTable::SortReorderByRowRefUpdate( | ||||
1161 | ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress ) | ||||
1162 | { | ||||
1163 | assert(pArray->IsUpdateRefs())(static_cast <bool> (pArray->IsUpdateRefs()) ? void ( 0) : __assert_fail ("pArray->IsUpdateRefs()", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 1163, __extension__ __PRETTY_FUNCTION__)); | ||||
1164 | |||||
1165 | if (nCol2 < nCol1) | ||||
1166 | return; | ||||
1167 | |||||
1168 | SCROW nRow1 = pArray->GetStart(); | ||||
1169 | SCROW nRow2 = pArray->GetLast(); | ||||
1170 | |||||
1171 | ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab); | ||||
1172 | sc::ColumnSpanSet aGrpListenerRanges; | ||||
1173 | |||||
1174 | { | ||||
1175 | // Get the range of formula group listeners within sorted range (if any). | ||||
1176 | sc::QueryRange aQuery; | ||||
1177 | |||||
1178 | ScBroadcastAreaSlotMachine* pBASM = rDocument.GetBASM(); | ||||
1179 | std::vector<sc::AreaListener> aGrpListeners = | ||||
1180 | pBASM->GetAllListeners( | ||||
1181 | aMoveRange, sc::AreaOverlapType::InsideOrOverlap, sc::ListenerGroupType::Group); | ||||
1182 | |||||
1183 | { | ||||
1184 | for (const auto& rGrpListener : aGrpListeners) | ||||
1185 | { | ||||
1186 | assert(rGrpListener.mbGroupListening)(static_cast <bool> (rGrpListener.mbGroupListening) ? void (0) : __assert_fail ("rGrpListener.mbGroupListening", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 1186, __extension__ __PRETTY_FUNCTION__)); | ||||
1187 | SvtListener* pGrpLis = rGrpListener.mpListener; | ||||
1188 | pGrpLis->Query(aQuery); | ||||
1189 | rDocument.EndListeningArea(rGrpListener.maArea, rGrpListener.mbGroupListening, pGrpLis); | ||||
1190 | } | ||||
1191 | } | ||||
1192 | |||||
1193 | ScRangeList aTmp; | ||||
1194 | aQuery.swapRanges(aTmp); | ||||
1195 | |||||
1196 | // If the range is within the sorted range, we need to expand its rows | ||||
1197 | // to the top and bottom of the sorted range, since the formula cells | ||||
1198 | // could be anywhere in the sorted range after reordering. | ||||
1199 | for (size_t i = 0, n = aTmp.size(); i < n; ++i) | ||||
1200 | { | ||||
1201 | ScRange aRange = aTmp[i]; | ||||
1202 | if (!aMoveRange.Intersects(aRange)) | ||||
1203 | { | ||||
1204 | // Doesn't overlap with the sorted range at all. | ||||
1205 | aGrpListenerRanges.set(GetDoc(), aRange, true); | ||||
1206 | continue; | ||||
1207 | } | ||||
1208 | |||||
1209 | if (aMoveRange.aStart.Col() <= aRange.aStart.Col() && aRange.aEnd.Col() <= aMoveRange.aEnd.Col()) | ||||
1210 | { | ||||
1211 | // Its column range is within the column range of the sorted range. | ||||
1212 | expandRowRange(aRange, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row()); | ||||
1213 | aGrpListenerRanges.set(GetDoc(), aRange, true); | ||||
1214 | continue; | ||||
1215 | } | ||||
1216 | |||||
1217 | // It intersects with the sorted range, but its column range is | ||||
1218 | // not within the column range of the sorted range. Split it into | ||||
1219 | // 2 ranges. | ||||
1220 | ScRange aR1 = aRange; | ||||
1221 | ScRange aR2 = aRange; | ||||
1222 | if (aRange.aStart.Col() < aMoveRange.aStart.Col()) | ||||
1223 | { | ||||
1224 | // Left half is outside the sorted range while the right half is inside. | ||||
1225 | aR1.aEnd.SetCol(aMoveRange.aStart.Col()-1); | ||||
1226 | aR2.aStart.SetCol(aMoveRange.aStart.Col()); | ||||
1227 | expandRowRange(aR2, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row()); | ||||
1228 | } | ||||
1229 | else | ||||
1230 | { | ||||
1231 | // Left half is inside the sorted range while the right half is outside. | ||||
1232 | aR1.aEnd.SetCol(aMoveRange.aEnd.Col()-1); | ||||
1233 | aR2.aStart.SetCol(aMoveRange.aEnd.Col()); | ||||
1234 | expandRowRange(aR1, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row()); | ||||
1235 | } | ||||
1236 | |||||
1237 | aGrpListenerRanges.set(GetDoc(), aR1, true); | ||||
1238 | aGrpListenerRanges.set(GetDoc(), aR2, true); | ||||
1239 | } | ||||
1240 | } | ||||
1241 | |||||
1242 | // Split formula groups at the sort range boundaries (if applicable). | ||||
1243 | std::vector<SCROW> aRowBounds; | ||||
1244 | aRowBounds.reserve(2); | ||||
1245 | aRowBounds.push_back(nRow1); | ||||
1246 | aRowBounds.push_back(nRow2+1); | ||||
1247 | for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) | ||||
1248 | SplitFormulaGroups(nCol, aRowBounds); | ||||
1249 | |||||
1250 | // Cells in the data rows only reference values in the document. Make | ||||
1251 | // a copy before updating the document. | ||||
1252 | std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells. | ||||
1253 | SortedRowFlags aRowFlags(GetDoc().GetSheetLimits()); | ||||
1254 | std::vector<SvtListener*> aListenersDummy; | ||||
1255 | fillSortedColumnArray(aSortedCols, aRowFlags, aListenersDummy, pArray, nTab, nCol1, nCol2, pProgress, this); | ||||
1256 | |||||
1257 | for (size_t i = 0, n = aSortedCols.size(); i < n; ++i) | ||||
1258 | { | ||||
1259 | SCCOL nThisCol = i + nCol1; | ||||
1260 | |||||
1261 | { | ||||
1262 | sc::CellStoreType& rDest = aCol[nThisCol].maCells; | ||||
1263 | sc::CellStoreType& rSrc = aSortedCols[i]->maCells; | ||||
1264 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1265 | } | ||||
1266 | |||||
1267 | { | ||||
1268 | sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs; | ||||
1269 | sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs; | ||||
1270 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1271 | } | ||||
1272 | |||||
1273 | { | ||||
1274 | sc::BroadcasterStoreType& rSrc = aSortedCols[i]->maBroadcasters; | ||||
1275 | sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters; | ||||
1276 | |||||
1277 | // Release current broadcasters first, to prevent them from getting deleted. | ||||
1278 | rDest.release_range(nRow1, nRow2); | ||||
1279 | |||||
1280 | // Transfer sorted broadcaster segment to the document. | ||||
1281 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1282 | } | ||||
1283 | |||||
1284 | { | ||||
1285 | sc::CellNoteStoreType& rSrc = aSortedCols[i]->maCellNotes; | ||||
1286 | sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes; | ||||
1287 | |||||
1288 | // Do the same as broadcaster storage transfer (to prevent double deletion). | ||||
1289 | rDest.release_range(nRow1, nRow2); | ||||
1290 | rSrc.transfer(nRow1, nRow2, rDest, nRow1); | ||||
1291 | aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2); | ||||
1292 | } | ||||
1293 | |||||
1294 | // Update draw object positions | ||||
1295 | aCol[nThisCol].UpdateDrawObjects(aSortedCols[i]->maCellDrawObjects, nRow1, nRow2); | ||||
1296 | |||||
1297 | { | ||||
1298 | // Get all row spans where the pattern is not NULL. | ||||
1299 | std::vector<PatternSpan> aSpans = | ||||
1300 | sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>( | ||||
1301 | aSortedCols[i]->maPatterns); | ||||
1302 | |||||
1303 | for (const auto& rSpan : aSpans) | ||||
1304 | { | ||||
1305 | assert(rSpan.mpPattern)(static_cast <bool> (rSpan.mpPattern) ? void (0) : __assert_fail ("rSpan.mpPattern", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 1305, __extension__ __PRETTY_FUNCTION__)); // should never be NULL. | ||||
1306 | rDocument.GetPool()->Put(*rSpan.mpPattern); | ||||
1307 | } | ||||
1308 | |||||
1309 | for (const auto& rSpan : aSpans) | ||||
1310 | { | ||||
1311 | aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern); | ||||
1312 | rDocument.GetPool()->Remove(*rSpan.mpPattern); | ||||
1313 | } | ||||
1314 | } | ||||
1315 | |||||
1316 | aCol[nThisCol].CellStorageModified(); | ||||
1317 | } | ||||
1318 | |||||
1319 | if (pArray->IsKeepQuery()) | ||||
1320 | { | ||||
1321 | aRowFlags.maRowsHidden.build_tree(); | ||||
1322 | aRowFlags.maRowsFiltered.build_tree(); | ||||
1323 | |||||
1324 | // Remove all flags in the range first. | ||||
1325 | SetRowHidden(nRow1, nRow2, false); | ||||
1326 | SetRowFiltered(nRow1, nRow2, false); | ||||
1327 | |||||
1328 | std::vector<sc::RowSpan> aSpans = | ||||
1329 | sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1); | ||||
1330 | |||||
1331 | for (const auto& rSpan : aSpans) | ||||
1332 | SetRowHidden(rSpan.mnRow1, rSpan.mnRow2, true); | ||||
1333 | |||||
1334 | aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1); | ||||
1335 | |||||
1336 | for (const auto& rSpan : aSpans) | ||||
1337 | SetRowFiltered(rSpan.mnRow1, rSpan.mnRow2, true); | ||||
1338 | } | ||||
1339 | |||||
1340 | // Set up row reorder map (for later broadcasting of reference updates). | ||||
1341 | sc::ColRowReorderMapType aRowMap; | ||||
1342 | const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices(); | ||||
1343 | for (size_t i = 0, n = rOldIndices.size(); i < n; ++i) | ||||
1344 | { | ||||
1345 | SCROW nNew = i + nRow1; | ||||
1346 | SCROW nOld = rOldIndices[i]; | ||||
1347 | aRowMap.emplace(nOld, nNew); | ||||
1348 | } | ||||
1349 | |||||
1350 | // Collect all listeners within sorted range ahead of time. | ||||
1351 | std::vector<SvtListener*> aListeners; | ||||
1352 | |||||
1353 | // Collect listeners of cell broadcasters. | ||||
1354 | for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) | ||||
1355 | aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); | ||||
1356 | |||||
1357 | // Get all area listeners that listen on one row within the range and end | ||||
1358 | // their listening. | ||||
1359 | std::vector<sc::AreaListener> aAreaListeners = rDocument.GetBASM()->GetAllListeners( | ||||
1360 | aMoveRange, sc::AreaOverlapType::OneRowInside); | ||||
1361 | { | ||||
1362 | for (auto& rAreaListener : aAreaListeners) | ||||
1363 | { | ||||
1364 | rDocument.EndListeningArea(rAreaListener.maArea, rAreaListener.mbGroupListening, rAreaListener.mpListener); | ||||
1365 | aListeners.push_back( rAreaListener.mpListener); | ||||
1366 | } | ||||
1367 | } | ||||
1368 | |||||
1369 | { | ||||
1370 | // Get all formula cells from the former group area listener ranges. | ||||
1371 | |||||
1372 | std::vector<ScFormulaCell*> aFCells; | ||||
1373 | FormulaCellCollectAction aAction(aFCells); | ||||
1374 | aGrpListenerRanges.executeColumnAction(rDocument, aAction); | ||||
1375 | |||||
1376 | aListeners.insert( aListeners.end(), aFCells.begin(), aFCells.end() ); | ||||
1377 | } | ||||
1378 | |||||
1379 | // Remove any duplicate listener entries. We must ensure that we notify | ||||
1380 | // each unique listener only once. | ||||
1381 | std::sort(aListeners.begin(), aListeners.end()); | ||||
1382 | aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end()); | ||||
1383 | |||||
1384 | // Collect positions of all shared formula cells outside the sorted range, | ||||
1385 | // and make them unshared before notifying them. | ||||
1386 | sc::RefQueryFormulaGroup aFormulaGroupPos; | ||||
1387 | aFormulaGroupPos.setSkipRange(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab)); | ||||
1388 | |||||
1389 | std::for_each(aListeners.begin(), aListeners.end(), FormulaGroupPosCollector(aFormulaGroupPos)); | ||||
1390 | const sc::RefQueryFormulaGroup::TabsType& rGroupTabs = aFormulaGroupPos.getAllPositions(); | ||||
1391 | for (const auto& [rTab, rCols] : rGroupTabs) | ||||
1392 | { | ||||
1393 | for (const auto& [nCol, rCol] : rCols) | ||||
1394 | { | ||||
1395 | std::vector<SCROW> aBounds(rCol); | ||||
1396 | rDocument.UnshareFormulaCells(rTab, nCol, aBounds); | ||||
1397 | } | ||||
1398 | } | ||||
1399 | |||||
1400 | // Notify the listeners to update their references. | ||||
1401 | ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> aFunc(aRowMap, nTab, nCol1, nCol2); | ||||
1402 | std::for_each(aListeners.begin(), aListeners.end(), aFunc); | ||||
1403 | |||||
1404 | // Re-group formulas in affected columns. | ||||
1405 | for (const auto& [rTab, rCols] : rGroupTabs) | ||||
1406 | { | ||||
1407 | for (const auto& rEntry : rCols) | ||||
1408 | rDocument.RegroupFormulaCells(rTab, rEntry.first); | ||||
1409 | } | ||||
1410 | |||||
1411 | // Re-start area listeners on the reordered rows. | ||||
1412 | for (const auto& rAreaListener : aAreaListeners) | ||||
1413 | { | ||||
1414 | ScRange aNewRange = rAreaListener.maArea; | ||||
1415 | sc::ColRowReorderMapType::const_iterator itRow = aRowMap.find( aNewRange.aStart.Row()); | ||||
1416 | if (itRow != aRowMap.end()) | ||||
1417 | { | ||||
1418 | aNewRange.aStart.SetRow( itRow->second); | ||||
1419 | aNewRange.aEnd.SetRow( itRow->second); | ||||
1420 | } | ||||
1421 | rDocument.StartListeningArea(aNewRange, rAreaListener.mbGroupListening, rAreaListener.mpListener); | ||||
1422 | } | ||||
1423 | |||||
1424 | // Re-group columns in the sorted range too. | ||||
1425 | for (SCCOL i = nCol1; i <= nCol2; ++i) | ||||
1426 | aCol[i].RegroupFormulaCells(); | ||||
1427 | |||||
1428 | { | ||||
1429 | // Re-start area listeners on the old group listener ranges. | ||||
1430 | ListenerStartAction aAction(rDocument); | ||||
1431 | aGrpListenerRanges.executeColumnAction(rDocument, aAction); | ||||
1432 | } | ||||
1433 | } | ||||
1434 | |||||
1435 | short ScTable::CompareCell( | ||||
1436 | sal_uInt16 nSort, | ||||
1437 | ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row, | ||||
1438 | ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const | ||||
1439 | { | ||||
1440 | short nRes = 0; | ||||
1441 | |||||
1442 | CellType eType1 = rCell1.meType, eType2 = rCell2.meType; | ||||
1443 | |||||
1444 | if (!rCell1.isEmpty()) | ||||
1445 | { | ||||
1446 | if (!rCell2.isEmpty()) | ||||
1447 | { | ||||
1448 | bool bErr1 = false; | ||||
1449 | bool bStr1 = ( eType1 != CELLTYPE_VALUE ); | ||||
1450 | if (eType1 == CELLTYPE_FORMULA) | ||||
1451 | { | ||||
1452 | if (rCell1.mpFormula->GetErrCode() != FormulaError::NONE) | ||||
1453 | { | ||||
1454 | bErr1 = true; | ||||
1455 | bStr1 = false; | ||||
1456 | } | ||||
1457 | else if (rCell1.mpFormula->IsValue()) | ||||
1458 | { | ||||
1459 | bStr1 = false; | ||||
1460 | } | ||||
1461 | } | ||||
1462 | |||||
1463 | bool bErr2 = false; | ||||
1464 | bool bStr2 = ( eType2 != CELLTYPE_VALUE ); | ||||
1465 | if (eType2 == CELLTYPE_FORMULA) | ||||
1466 | { | ||||
1467 | if (rCell2.mpFormula->GetErrCode() != FormulaError::NONE) | ||||
1468 | { | ||||
1469 | bErr2 = true; | ||||
1470 | bStr2 = false; | ||||
1471 | } | ||||
1472 | else if (rCell2.mpFormula->IsValue()) | ||||
1473 | { | ||||
1474 | bStr2 = false; | ||||
1475 | } | ||||
1476 | } | ||||
1477 | |||||
1478 | if ( bStr1 && bStr2 ) // only compare strings as strings! | ||||
1479 | { | ||||
1480 | OUString aStr1; | ||||
1481 | OUString aStr2; | ||||
1482 | if (eType1 == CELLTYPE_STRING) | ||||
1483 | aStr1 = rCell1.mpString->getString(); | ||||
1484 | else | ||||
1485 | GetString(nCell1Col, nCell1Row, aStr1); | ||||
1486 | if (eType2 == CELLTYPE_STRING) | ||||
1487 | aStr2 = rCell2.mpString->getString(); | ||||
1488 | else | ||||
1489 | GetString(nCell2Col, nCell2Row, aStr2); | ||||
1490 | |||||
1491 | bool bUserDef = aSortParam.bUserDef; // custom sort order | ||||
1492 | bool bNaturalSort = aSortParam.bNaturalSort; // natural sort | ||||
1493 | bool bCaseSens = aSortParam.bCaseSens; // case sensitivity | ||||
1494 | |||||
1495 | ScUserList* pList = ScGlobal::GetUserList(); | ||||
1496 | if (bUserDef && pList && pList->size() > aSortParam.nUserIndex ) | ||||
1497 | { | ||||
1498 | const ScUserListData& rData = (*pList)[aSortParam.nUserIndex]; | ||||
1499 | |||||
1500 | if ( bNaturalSort ) | ||||
1501 | nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, &rData, pSortCollator ); | ||||
1502 | else | ||||
1503 | { | ||||
1504 | if ( bCaseSens ) | ||||
1505 | nRes = sal::static_int_cast<short>( rData.Compare(aStr1, aStr2) ); | ||||
1506 | else | ||||
1507 | nRes = sal::static_int_cast<short>( rData.ICompare(aStr1, aStr2) ); | ||||
1508 | } | ||||
1509 | |||||
1510 | } | ||||
1511 | if (!bUserDef) | ||||
1512 | { | ||||
1513 | if ( bNaturalSort ) | ||||
1514 | nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, nullptr, pSortCollator ); | ||||
1515 | else | ||||
1516 | nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) ); | ||||
1517 | } | ||||
1518 | } | ||||
1519 | else if ( bStr1 ) // String <-> Number or Error | ||||
1520 | { | ||||
1521 | if (bErr2) | ||||
1522 | nRes = -1; // String in front of Error | ||||
1523 | else | ||||
1524 | nRes = 1; // Number in front of String | ||||
1525 | } | ||||
1526 | else if ( bStr2 ) // Number or Error <-> String | ||||
1527 | { | ||||
1528 | if (bErr1) | ||||
1529 | nRes = 1; // String in front of Error | ||||
1530 | else | ||||
1531 | nRes = -1; // Number in front of String | ||||
1532 | } | ||||
1533 | else if (bErr1 && bErr2) | ||||
1534 | { | ||||
1535 | // nothing, two Errors are equal | ||||
1536 | } | ||||
1537 | else if (bErr1) // Error <-> Number | ||||
1538 | { | ||||
1539 | nRes = 1; // Number in front of Error | ||||
1540 | } | ||||
1541 | else if (bErr2) // Number <-> Error | ||||
1542 | { | ||||
1543 | nRes = -1; // Number in front of Error | ||||
1544 | } | ||||
1545 | else // Mixed numbers | ||||
1546 | { | ||||
1547 | double nVal1 = rCell1.getValue(); | ||||
1548 | double nVal2 = rCell2.getValue(); | ||||
1549 | if (nVal1 < nVal2) | ||||
1550 | nRes = -1; | ||||
1551 | else if (nVal1 > nVal2) | ||||
1552 | nRes = 1; | ||||
1553 | } | ||||
1554 | if ( !aSortParam.maKeyState[nSort].bAscending ) | ||||
1555 | nRes = -nRes; | ||||
1556 | } | ||||
1557 | else | ||||
1558 | nRes = -1; | ||||
1559 | } | ||||
1560 | else | ||||
1561 | { | ||||
1562 | if (!rCell2.isEmpty()) | ||||
1563 | nRes = 1; | ||||
1564 | else | ||||
1565 | nRes = 0; // both empty | ||||
1566 | } | ||||
1567 | return nRes; | ||||
1568 | } | ||||
1569 | |||||
1570 | short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const | ||||
1571 | { | ||||
1572 | short nRes; | ||||
1573 | sal_uInt16 nSort = 0; | ||||
1574 | do | ||||
1575 | { | ||||
1576 | ScSortInfo& rInfo1 = pArray->Get( nSort, nIndex1 ); | ||||
1577 | ScSortInfo& rInfo2 = pArray->Get( nSort, nIndex2 ); | ||||
1578 | if ( aSortParam.bByRow ) | ||||
1579 | nRes = CompareCell( nSort, | ||||
1580 | rInfo1.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo1.nOrg, | ||||
1581 | rInfo2.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo2.nOrg ); | ||||
1582 | else | ||||
1583 | nRes = CompareCell( nSort, | ||||
1584 | rInfo1.maCell, static_cast<SCCOL>(rInfo1.nOrg), aSortParam.maKeyState[nSort].nField, | ||||
1585 | rInfo2.maCell, static_cast<SCCOL>(rInfo2.nOrg), aSortParam.maKeyState[nSort].nField ); | ||||
1586 | } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() ); | ||||
1587 | if( nRes == 0 ) | ||||
1588 | { | ||||
1589 | ScSortInfo& rInfo1 = pArray->Get( 0, nIndex1 ); | ||||
1590 | ScSortInfo& rInfo2 = pArray->Get( 0, nIndex2 ); | ||||
1591 | if( rInfo1.nOrg < rInfo2.nOrg ) | ||||
1592 | nRes = -1; | ||||
1593 | else if( rInfo1.nOrg > rInfo2.nOrg ) | ||||
1594 | nRes = 1; | ||||
1595 | } | ||||
1596 | return nRes; | ||||
1597 | } | ||||
1598 | |||||
1599 | void ScTable::QuickSort( ScSortInfoArray* pArray, SCCOLROW nLo, SCCOLROW nHi ) | ||||
1600 | { | ||||
1601 | if ((nHi - nLo) == 1) | ||||
1602 | { | ||||
1603 | if (Compare(pArray, nLo, nHi) > 0) | ||||
1604 | pArray->Swap( nLo, nHi ); | ||||
1605 | } | ||||
1606 | else | ||||
1607 | { | ||||
1608 | SCCOLROW ni = nLo; | ||||
1609 | SCCOLROW nj = nHi; | ||||
1610 | do | ||||
1611 | { | ||||
1612 | while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0) | ||||
1613 | ni++; | ||||
1614 | while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0) | ||||
1615 | nj--; | ||||
1616 | if (ni <= nj) | ||||
1617 | { | ||||
1618 | if (ni != nj) | ||||
1619 | pArray->Swap( ni, nj ); | ||||
1620 | ni++; | ||||
1621 | nj--; | ||||
1622 | } | ||||
1623 | } while (ni < nj); | ||||
1624 | if ((nj - nLo) < (nHi - ni)) | ||||
1625 | { | ||||
1626 | if (nLo < nj) | ||||
1627 | QuickSort(pArray, nLo, nj); | ||||
1628 | if (ni < nHi) | ||||
1629 | QuickSort(pArray, ni, nHi); | ||||
1630 | } | ||||
1631 | else | ||||
1632 | { | ||||
1633 | if (ni < nHi) | ||||
1634 | QuickSort(pArray, ni, nHi); | ||||
1635 | if (nLo < nj) | ||||
1636 | QuickSort(pArray, nLo, nj); | ||||
1637 | } | ||||
1638 | } | ||||
1639 | } | ||||
1640 | |||||
1641 | short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const | ||||
1642 | { | ||||
1643 | short nRes; | ||||
1644 | sal_uInt16 nSort = 0; | ||||
1645 | const sal_uInt32 nMaxSorts = aSortParam.GetSortKeyCount(); | ||||
1646 | if (aSortParam.bByRow) | ||||
1647 | { | ||||
1648 | do | ||||
1649 | { | ||||
1650 | SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField); | ||||
1651 | ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1); | ||||
1652 | ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2); | ||||
1653 | nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2); | ||||
1654 | } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort ); | ||||
1655 | } | ||||
1656 | else | ||||
1657 | { | ||||
1658 | do | ||||
1659 | { | ||||
1660 | SCROW nRow = aSortParam.maKeyState[nSort].nField; | ||||
1661 | ScRefCellValue aCell1 = aCol[nIndex1].GetCellValue(nRow); | ||||
1662 | ScRefCellValue aCell2 = aCol[nIndex2].GetCellValue(nRow); | ||||
1663 | nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1), | ||||
1664 | nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow ); | ||||
1665 | } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort ); | ||||
1666 | } | ||||
1667 | return nRes; | ||||
1668 | } | ||||
1669 | |||||
1670 | bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) const // over aSortParam | ||||
1671 | { | ||||
1672 | for (SCCOLROW i=nStart; i<nEnd; i++) | ||||
1673 | { | ||||
1674 | if (Compare( i, i+1 ) > 0) | ||||
1675 | return false; | ||||
1676 | } | ||||
1677 | return true; | ||||
1678 | } | ||||
1679 | |||||
1680 | void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 ) | ||||
1681 | { | ||||
1682 | SCROW nRow; | ||||
1683 | int nMax = nRow2 - nRow1; | ||||
1684 | for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4) | ||||
1685 | { | ||||
1686 | nRow = comphelper::rng::uniform_int_distribution(0, nMax-1); | ||||
1687 | pArray->Swap(i, nRow1 + nRow); | ||||
1688 | } | ||||
1689 | } | ||||
1690 | |||||
1691 | void ScTable::Sort( | ||||
1692 | const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs, | ||||
1693 | ScProgress* pProgress, sc::ReorderParam* pUndo ) | ||||
1694 | { | ||||
1695 | InitSortCollator( rSortParam ); | ||||
1696 | bGlobalKeepQuery = bKeepQuery; | ||||
1697 | |||||
1698 | if (pUndo) | ||||
1699 | { | ||||
1700 | // Copy over the basic sort parameters. | ||||
1701 | pUndo->mbByRow = rSortParam.bByRow; | ||||
1702 | pUndo->mbPattern = rSortParam.bIncludePattern; | ||||
1703 | pUndo->mbHiddenFiltered = bKeepQuery; | ||||
1704 | pUndo->mbUpdateRefs = bUpdateRefs; | ||||
1705 | pUndo->mbHasHeaders = rSortParam.bHasHeader; | ||||
1706 | } | ||||
1707 | |||||
1708 | // It is assumed that the data area has already been trimmed as necessary. | ||||
1709 | |||||
1710 | aSortParam = rSortParam; // must be assigned before calling IsSorted() | ||||
1711 | if (rSortParam.bByRow) | ||||
1712 | { | ||||
1713 | SCROW nLastRow = rSortParam.nRow2; | ||||
1714 | SCROW nRow1 = (rSortParam.bHasHeader ? rSortParam.nRow1 + 1 : rSortParam.nRow1); | ||||
1715 | if (nRow1 < nLastRow && !IsSorted(nRow1, nLastRow)) | ||||
1716 | { | ||||
1717 | if(pProgress) | ||||
1718 | pProgress->SetState( 0, nLastRow-nRow1 ); | ||||
1719 | |||||
1720 | std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs)); | ||||
1721 | |||||
1722 | if ( nLastRow - nRow1 > 255 ) | ||||
1723 | DecoladeRow(pArray.get(), nRow1, nLastRow); | ||||
1724 | |||||
1725 | QuickSort(pArray.get(), nRow1, nLastRow); | ||||
1726 | if (pArray->IsUpdateRefs()) | ||||
1727 | SortReorderByRowRefUpdate(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress); | ||||
1728 | else | ||||
1729 | SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress); | ||||
1730 | |||||
1731 | if (pUndo) | ||||
1732 | { | ||||
1733 | pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab); | ||||
1734 | pUndo->maOrderIndices = pArray->GetOrderIndices(); | ||||
1735 | } | ||||
1736 | } | ||||
1737 | } | ||||
1738 | else | ||||
1739 | { | ||||
1740 | SCCOL nLastCol = rSortParam.nCol2; | ||||
1741 | SCCOL nCol1 = (rSortParam.bHasHeader ? rSortParam.nCol1 + 1 : rSortParam.nCol1); | ||||
1742 | if (nCol1 < nLastCol && !IsSorted(nCol1, nLastCol)) | ||||
1743 | { | ||||
1744 | if(pProgress) | ||||
1745 | pProgress->SetState( 0, nLastCol-nCol1 ); | ||||
1746 | |||||
1747 | std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs)); | ||||
1748 | |||||
1749 | QuickSort(pArray.get(), nCol1, nLastCol); | ||||
1750 | SortReorderByColumn(pArray.get(), aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern, pProgress); | ||||
1751 | |||||
1752 | if (pUndo) | ||||
1753 | { | ||||
1754 | pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab); | ||||
1755 | pUndo->maOrderIndices = pArray->GetOrderIndices(); | ||||
1756 | } | ||||
1757 | } | ||||
1758 | } | ||||
1759 | DestroySortCollator(); | ||||
1760 | } | ||||
1761 | |||||
1762 | void ScTable::Reorder( const sc::ReorderParam& rParam ) | ||||
1763 | { | ||||
1764 | if (rParam.maOrderIndices.empty()) | ||||
1765 | return; | ||||
1766 | |||||
1767 | std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(rParam)); | ||||
1768 | if (!pArray) | ||||
1769 | return; | ||||
1770 | |||||
1771 | if (rParam.mbByRow) | ||||
1772 | { | ||||
1773 | // Re-play sorting from the known sort indices. | ||||
1774 | pArray->ReorderByRow(rParam.maOrderIndices); | ||||
1775 | if (pArray->IsUpdateRefs()) | ||||
1776 | SortReorderByRowRefUpdate( | ||||
1777 | pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr); | ||||
1778 | else | ||||
1779 | SortReorderByRow( | ||||
1780 | pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr); | ||||
1781 | } | ||||
1782 | else | ||||
1783 | { | ||||
1784 | // Ordering by column is much simpler. Just set the order indices and we are done. | ||||
1785 | pArray->SetOrderIndices(rParam.maOrderIndices); | ||||
1786 | SortReorderByColumn( | ||||
1787 | pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(), | ||||
1788 | rParam.mbPattern, nullptr); | ||||
1789 | } | ||||
1790 | } | ||||
1791 | |||||
1792 | namespace { | ||||
1793 | |||||
1794 | class SubTotalRowFinder | ||||
1795 | { | ||||
1796 | const ScTable& mrTab; | ||||
1797 | const ScSubTotalParam& mrParam; | ||||
1798 | |||||
1799 | public: | ||||
1800 | SubTotalRowFinder(const ScTable& rTab, const ScSubTotalParam& rParam) : | ||||
1801 | mrTab(rTab), mrParam(rParam) {} | ||||
1802 | |||||
1803 | bool operator() (size_t nRow, const ScFormulaCell* pCell) | ||||
1804 | { | ||||
1805 | if (!pCell->IsSubTotal()) | ||||
1806 | return false; | ||||
1807 | |||||
1808 | SCCOL nStartCol = mrParam.nCol1; | ||||
1809 | SCCOL nEndCol = mrParam.nCol2; | ||||
1810 | |||||
1811 | for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1)) | ||||
1812 | { | ||||
1813 | if (mrTab.HasData(nCol, nRow)) | ||||
1814 | return true; | ||||
1815 | } | ||||
1816 | for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol())) | ||||
1817 | { | ||||
1818 | if (mrTab.HasData(nCol, nRow)) | ||||
1819 | return true; | ||||
1820 | } | ||||
1821 | return false; | ||||
1822 | } | ||||
1823 | }; | ||||
1824 | |||||
1825 | } | ||||
1826 | |||||
1827 | bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam ) | ||||
1828 | { | ||||
1829 | SCCOL nStartCol = rParam.nCol1; | ||||
1830 | SCROW nStartRow = rParam.nRow1 + 1; // Header | ||||
1831 | SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2); | ||||
1832 | SCROW nEndRow = rParam.nRow2; | ||||
1833 | |||||
1834 | for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol) | ||||
1835 | { | ||||
1836 | const sc::CellStoreType& rCells = aCol[nCol].maCells; | ||||
1837 | SubTotalRowFinder aFunc(*this, rParam); | ||||
1838 | std::pair<sc::CellStoreType::const_iterator,size_t> aPos = | ||||
1839 | sc::FindFormula(rCells, nStartRow, nEndRow, aFunc); | ||||
1840 | if (aPos.first != rCells.end()) | ||||
1841 | return true; | ||||
1842 | } | ||||
1843 | return false; | ||||
1844 | } | ||||
1845 | |||||
1846 | namespace { | ||||
1847 | |||||
1848 | struct RemoveSubTotalsHandler | ||||
1849 | { | ||||
1850 | std::set<SCROW> aRemoved; | ||||
1851 | |||||
1852 | void operator() (size_t nRow, const ScFormulaCell* p) | ||||
1853 | { | ||||
1854 | if (p->IsSubTotal()) | ||||
1855 | aRemoved.insert(nRow); | ||||
1856 | } | ||||
1857 | }; | ||||
1858 | |||||
1859 | } | ||||
1860 | |||||
1861 | void ScTable::RemoveSubTotals( ScSubTotalParam& rParam ) | ||||
1862 | { | ||||
1863 | SCCOL nStartCol = rParam.nCol1; | ||||
1864 | SCROW nStartRow = rParam.nRow1 + 1; // Header | ||||
1865 | SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2); | ||||
1866 | SCROW nEndRow = rParam.nRow2; // will change | ||||
1867 | |||||
1868 | RemoveSubTotalsHandler aFunc; | ||||
1869 | for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol) | ||||
1870 | { | ||||
1871 | const sc::CellStoreType& rCells = aCol[nCol].maCells; | ||||
1872 | sc::ParseFormula(rCells.begin(), rCells, nStartRow, nEndRow, aFunc); | ||||
1873 | } | ||||
1874 | |||||
1875 | auto& aRows = aFunc.aRemoved; | ||||
1876 | |||||
1877 | std::for_each(aRows.rbegin(), aRows.rend(), [this](const SCROW nRow) { | ||||
1878 | RemoveRowBreak(nRow+1, false, true); | ||||
1879 | rDocument.DeleteRow(0, nTab, rDocument.MaxCol(), nTab, nRow, 1); | ||||
1880 | }); | ||||
1881 | |||||
1882 | rParam.nRow2 -= aRows.size(); | ||||
1883 | } | ||||
1884 | |||||
1885 | // Delete hard number formats (for result formulas) | ||||
1886 | |||||
1887 | static void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow ) | ||||
1888 | { | ||||
1889 | const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow ); | ||||
1890 | if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false ) | ||||
1891 | == SfxItemState::SET ) | ||||
1892 | { | ||||
1893 | auto pNewPattern = std::make_unique<ScPatternAttr>( *pPattern ); | ||||
1894 | SfxItemSet& rSet = pNewPattern->GetItemSet(); | ||||
1895 | rSet.ClearItem( ATTR_VALUE_FORMAT ); | ||||
1896 | rSet.ClearItem( ATTR_LANGUAGE_FORMAT ); | ||||
1897 | pTab->SetPattern( nCol, nRow, std::move(pNewPattern) ); | ||||
1898 | } | ||||
1899 | } | ||||
1900 | |||||
1901 | namespace { | ||||
1902 | |||||
1903 | struct RowEntry | ||||
1904 | { | ||||
1905 | sal_uInt16 nGroupNo; | ||||
1906 | SCROW nSubStartRow; | ||||
1907 | SCROW nDestRow; | ||||
1908 | SCROW nFuncStart; | ||||
1909 | SCROW nFuncEnd; | ||||
1910 | }; | ||||
1911 | |||||
1912 | } | ||||
1913 | |||||
1914 | static const char* lcl_GetSubTotalStrId(int id) | ||||
1915 | { | ||||
1916 | switch ( id ) | ||||
1917 | { | ||||
1918 | case SUBTOTAL_FUNC_AVE: return STR_FUN_TEXT_AVGreinterpret_cast<char const *>("STR_FUN_TEXT_AVG" "\004" u8"Average"); | ||||
1919 | case SUBTOTAL_FUNC_CNT: | ||||
1920 | case SUBTOTAL_FUNC_CNT2: return STR_FUN_TEXT_COUNTreinterpret_cast<char const *>("STR_FUN_TEXT_COUNT" "\004" u8"Count"); | ||||
1921 | case SUBTOTAL_FUNC_MAX: return STR_FUN_TEXT_MAXreinterpret_cast<char const *>("STR_FUN_TEXT_MAX" "\004" u8"Max"); | ||||
1922 | case SUBTOTAL_FUNC_MIN: return STR_FUN_TEXT_MINreinterpret_cast<char const *>("STR_FUN_TEXT_MIN" "\004" u8"Min"); | ||||
1923 | case SUBTOTAL_FUNC_PROD: return STR_FUN_TEXT_PRODUCTreinterpret_cast<char const *>("STR_FUN_TEXT_PRODUCT" "\004" u8"Product"); | ||||
1924 | case SUBTOTAL_FUNC_STD: | ||||
1925 | case SUBTOTAL_FUNC_STDP: return STR_FUN_TEXT_STDDEVreinterpret_cast<char const *>("STR_FUN_TEXT_STDDEV" "\004" u8"StDev"); | ||||
1926 | case SUBTOTAL_FUNC_SUM: return STR_FUN_TEXT_SUMreinterpret_cast<char const *>("STR_FUN_TEXT_SUM" "\004" u8"Sum"); | ||||
1927 | case SUBTOTAL_FUNC_VAR: | ||||
1928 | case SUBTOTAL_FUNC_VARP: return STR_FUN_TEXT_VARreinterpret_cast<char const *>("STR_FUN_TEXT_VAR" "\004" u8"Var"); | ||||
1929 | default: | ||||
1930 | { | ||||
1931 | return STR_EMPTYDATAreinterpret_cast<char const *>("STR_EMPTYDATA" "\004" u8"(empty)" ); | ||||
1932 | // added to avoid warnings | ||||
1933 | } | ||||
1934 | } | ||||
1935 | } | ||||
1936 | |||||
1937 | // new intermediate results | ||||
1938 | // rParam.nRow2 is changed! | ||||
1939 | |||||
1940 | bool ScTable::DoSubTotals( ScSubTotalParam& rParam ) | ||||
1941 | { | ||||
1942 | SCCOL nStartCol = rParam.nCol1; | ||||
1943 | SCROW nStartRow = rParam.nRow1 + 1; // Header | ||||
1944 | SCCOL nEndCol = rParam.nCol2; | ||||
1945 | SCROW nEndRow = rParam.nRow2; // will change | ||||
1946 | sal_uInt16 i; | ||||
1947 | |||||
1948 | // Remove empty rows at the end | ||||
1949 | // so that all exceeding (rDocument.MaxRow()) can be found by InsertRow (#35180#) | ||||
1950 | // If sorted, all empty rows are at the end. | ||||
1951 | SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM ); | ||||
1952 | nEndRow -= nEmpty; | ||||
1953 | |||||
1954 | sal_uInt16 nLevelCount = 0; // Number of levels | ||||
1955 | bool bDoThis = true; | ||||
1956 | for (i=0; i<MAXSUBTOTAL && bDoThis; i++) | ||||
1957 | if (rParam.bGroupActive[i]) | ||||
1958 | nLevelCount = i+1; | ||||
1959 | else | ||||
1960 | bDoThis = false; | ||||
1961 | |||||
1962 | if (nLevelCount==0) // do nothing | ||||
1963 | return true; | ||||
1964 | |||||
1965 | SCCOL* nGroupCol = rParam.nField; // columns which will be used when grouping | ||||
1966 | |||||
1967 | // With (blank) as a separate category, subtotal rows from | ||||
1968 | // the other columns must always be tested | ||||
1969 | // (previously only when a column occurred more than once) | ||||
1970 | bool bTestPrevSub = ( nLevelCount > 1 ); | ||||
1971 | |||||
1972 | OUString aSubString; | ||||
1973 | |||||
1974 | bool bIgnoreCase = !rParam.bCaseSens; | ||||
1975 | |||||
1976 | OUString aCompString[MAXSUBTOTAL]; | ||||
1977 | |||||
1978 | //TODO: sort? | ||||
1979 | |||||
1980 | ScStyleSheet* pStyle = static_cast<ScStyleSheet*>(rDocument.GetStyleSheetPool()->Find( | ||||
1981 | ScResId(STR_STYLENAME_RESULTreinterpret_cast<char const *>("STR_STYLENAME_RESULT" "\004" u8"Result")), SfxStyleFamily::Para )); | ||||
1982 | |||||
1983 | bool bSpaceLeft = true; // Success when inserting? | ||||
1984 | |||||
1985 | // For performance reasons collect formula entries so their | ||||
1986 | // references don't have to be tested for updates each time a new row is | ||||
1987 | // inserted | ||||
1988 | RowEntry aRowEntry; | ||||
1989 | ::std::vector< RowEntry > aRowVector; | ||||
1990 | |||||
1991 | for (sal_uInt16 nLevel=0; nLevel<nLevelCount && bSpaceLeft; nLevel++) | ||||
1992 | { | ||||
1993 | aRowEntry.nGroupNo = nLevelCount - nLevel - 1; | ||||
1994 | |||||
1995 | // how many results per level | ||||
1996 | SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo]; | ||||
1997 | // result functions | ||||
1998 | ScSubTotalFunc* pResFunc = rParam.pFunctions[aRowEntry.nGroupNo]; | ||||
1999 | |||||
2000 | if (nResCount > 0) // otherwise only sort | ||||
2001 | { | ||||
2002 | for (i=0; i<=aRowEntry.nGroupNo; i++) | ||||
2003 | { | ||||
2004 | GetString( nGroupCol[i], nStartRow, aSubString ); | ||||
2005 | if ( bIgnoreCase ) | ||||
2006 | aCompString[i] = ScGlobal::getCharClassPtr()->uppercase( aSubString ); | ||||
2007 | else | ||||
2008 | aCompString[i] = aSubString; | ||||
2009 | } // aSubString stays on the last | ||||
2010 | |||||
2011 | bool bBlockVis = false; // group visible? | ||||
2012 | aRowEntry.nSubStartRow = nStartRow; | ||||
2013 | for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++) | ||||
2014 | { | ||||
2015 | bool bChanged; | ||||
2016 | if (nRow>nEndRow) | ||||
2017 | bChanged = true; | ||||
2018 | else | ||||
2019 | { | ||||
2020 | bChanged = false; | ||||
2021 | OUString aString; | ||||
2022 | for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++) | ||||
2023 | { | ||||
2024 | GetString( nGroupCol[i], nRow, aString ); | ||||
2025 | if (bIgnoreCase) | ||||
2026 | aString = ScGlobal::getCharClassPtr()->uppercase(aString); | ||||
2027 | // when sorting, blanks are separate group | ||||
2028 | // otherwise blank cells are allowed below | ||||
2029 | bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) && | ||||
2030 | aString != aCompString[i] ); | ||||
2031 | } | ||||
2032 | if ( bChanged && bTestPrevSub ) | ||||
2033 | { | ||||
2034 | // No group change on rows that will contain subtotal formulas | ||||
2035 | bChanged = std::none_of(aRowVector.begin(), aRowVector.end(), | ||||
2036 | [&nRow](const RowEntry& rEntry) { return rEntry.nDestRow == nRow; }); | ||||
2037 | } | ||||
2038 | } | ||||
2039 | if ( bChanged ) | ||||
2040 | { | ||||
2041 | aRowEntry.nDestRow = nRow; | ||||
2042 | aRowEntry.nFuncStart = aRowEntry.nSubStartRow; | ||||
2043 | aRowEntry.nFuncEnd = nRow-1; | ||||
2044 | |||||
2045 | bSpaceLeft = rDocument.InsertRow( 0, nTab, rDocument.MaxCol(), nTab, | ||||
2046 | aRowEntry.nDestRow, 1 ); | ||||
2047 | DBShowRow( aRowEntry.nDestRow, bBlockVis ); | ||||
2048 | if ( rParam.bPagebreak && nRow < rDocument.MaxRow() && | ||||
2049 | aRowEntry.nSubStartRow != nStartRow && nLevel == 0) | ||||
2050 | SetRowBreak(aRowEntry.nSubStartRow, false, true); | ||||
2051 | |||||
2052 | if (bSpaceLeft) | ||||
2053 | { | ||||
2054 | for ( auto& rRowEntry : aRowVector) | ||||
2055 | { | ||||
2056 | if ( aRowEntry.nDestRow <= rRowEntry.nSubStartRow ) | ||||
2057 | ++rRowEntry.nSubStartRow; | ||||
2058 | if ( aRowEntry.nDestRow <= rRowEntry.nDestRow ) | ||||
2059 | ++rRowEntry.nDestRow; | ||||
2060 | if ( aRowEntry.nDestRow <= rRowEntry.nFuncStart ) | ||||
2061 | ++rRowEntry.nFuncStart; | ||||
2062 | if ( aRowEntry.nDestRow <= rRowEntry.nFuncEnd ) | ||||
2063 | ++rRowEntry.nFuncEnd; | ||||
2064 | } | ||||
2065 | // collect formula positions | ||||
2066 | aRowVector.push_back( aRowEntry ); | ||||
2067 | |||||
2068 | OUString aOutString = aSubString; | ||||
2069 | if (aOutString.isEmpty()) | ||||
2070 | aOutString = ScResId( STR_EMPTYDATAreinterpret_cast<char const *>("STR_EMPTYDATA" "\004" u8"(empty)" ) ); | ||||
2071 | aOutString += " "; | ||||
2072 | const char* pStrId = STR_TABLE_ERGEBNISreinterpret_cast<char const *>("STR_TABLE_ERGEBNIS" "\004" u8"Result"); | ||||
2073 | if ( nResCount == 1 ) | ||||
2074 | pStrId = lcl_GetSubTotalStrId(pResFunc[0]); | ||||
2075 | aOutString += ScResId(pStrId); | ||||
2076 | SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString ); | ||||
2077 | ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle ); | ||||
2078 | |||||
2079 | ++nRow; | ||||
2080 | ++nEndRow; | ||||
2081 | aRowEntry.nSubStartRow = nRow; | ||||
2082 | for (i=0; i<=aRowEntry.nGroupNo; i++) | ||||
2083 | { | ||||
2084 | GetString( nGroupCol[i], nRow, aSubString ); | ||||
2085 | if ( bIgnoreCase ) | ||||
2086 | aCompString[i] = ScGlobal::getCharClassPtr()->uppercase( aSubString ); | ||||
2087 | else | ||||
2088 | aCompString[i] = aSubString; | ||||
2089 | } | ||||
2090 | } | ||||
2091 | } | ||||
2092 | bBlockVis = !RowFiltered(nRow); | ||||
2093 | } | ||||
2094 | } | ||||
2095 | } | ||||
2096 | |||||
2097 | if (!aRowVector.empty()) | ||||
2098 | { | ||||
2099 | // generate global total | ||||
2100 | SCROW nGlobalStartRow = aRowVector[0].nSubStartRow; | ||||
2101 | SCROW nGlobalStartFunc = aRowVector[0].nFuncStart; | ||||
2102 | SCROW nGlobalEndRow = 0; | ||||
2103 | SCROW nGlobalEndFunc = 0; | ||||
2104 | for (const auto& rRowEntry : aRowVector) | ||||
2105 | { | ||||
2106 | nGlobalEndRow = (nGlobalEndRow < rRowEntry.nDestRow) ? rRowEntry.nDestRow : nGlobalEndRow; | ||||
2107 | nGlobalEndFunc = (nGlobalEndFunc < rRowEntry.nFuncEnd) ? rRowEntry.nFuncEnd : nGlobalEndRow; | ||||
2108 | } | ||||
2109 | |||||
2110 | for (sal_uInt16 nLevel = 0; nLevel<nLevelCount; nLevel++) | ||||
2111 | { | ||||
2112 | const sal_uInt16 nGroupNo = nLevelCount - nLevel - 1; | ||||
2113 | const ScSubTotalFunc* pResFunc = rParam.pFunctions[nGroupNo]; | ||||
2114 | if (!pResFunc) | ||||
2115 | { | ||||
2116 | // No subtotal function given for this group => no formula or | ||||
2117 | // label and do not insert a row. | ||||
2118 | continue; | ||||
2119 | } | ||||
2120 | |||||
2121 | // increment end row | ||||
2122 | nGlobalEndRow++; | ||||
2123 | |||||
2124 | // add row entry for formula | ||||
2125 | aRowEntry.nGroupNo = nGroupNo; | ||||
2126 | aRowEntry.nSubStartRow = nGlobalStartRow; | ||||
2127 | aRowEntry.nFuncStart = nGlobalStartFunc; | ||||
2128 | aRowEntry.nDestRow = nGlobalEndRow; | ||||
2129 | aRowEntry.nFuncEnd = nGlobalEndFunc; | ||||
2130 | |||||
2131 | // increment row | ||||
2132 | nGlobalEndFunc++; | ||||
2133 | |||||
2134 | bSpaceLeft = rDocument.InsertRow(0, nTab, rDocument.MaxCol(), nTab, aRowEntry.nDestRow, 1); | ||||
2135 | |||||
2136 | if (bSpaceLeft) | ||||
2137 | { | ||||
2138 | aRowVector.push_back(aRowEntry); | ||||
2139 | nEndRow++; | ||||
2140 | DBShowRow(aRowEntry.nDestRow, true); | ||||
2141 | |||||
2142 | // insert label | ||||
2143 | OUString label = ScResId(STR_TABLE_GRANDreinterpret_cast<char const *>("STR_TABLE_GRAND" "\004" u8"Grand")) + " " + ScResId(lcl_GetSubTotalStrId(pResFunc[0])); | ||||
2144 | SetString(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, label); | ||||
2145 | ApplyStyle(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle); | ||||
2146 | } | ||||
2147 | } | ||||
2148 | } | ||||
2149 | |||||
2150 | // now insert the formulas | ||||
2151 | ScComplexRefData aRef; | ||||
2152 | aRef.InitFlags(); | ||||
2153 | aRef.Ref1.SetAbsTab(nTab); | ||||
2154 | aRef.Ref2.SetAbsTab(nTab); | ||||
2155 | for (const auto& rRowEntry : aRowVector) | ||||
2156 | { | ||||
2157 | SCCOL nResCount = rParam.nSubTotals[rRowEntry.nGroupNo]; | ||||
2158 | SCCOL* nResCols = rParam.pSubTotals[rRowEntry.nGroupNo]; | ||||
2159 | ScSubTotalFunc* pResFunc = rParam.pFunctions[rRowEntry.nGroupNo]; | ||||
2160 | for ( SCCOL nResult=0; nResult < nResCount; ++nResult ) | ||||
2161 | { | ||||
2162 | aRef.Ref1.SetAbsCol(nResCols[nResult]); | ||||
2163 | aRef.Ref1.SetAbsRow(rRowEntry.nFuncStart); | ||||
2164 | aRef.Ref2.SetAbsCol(nResCols[nResult]); | ||||
2165 | aRef.Ref2.SetAbsRow(rRowEntry.nFuncEnd); | ||||
2166 | |||||
2167 | ScTokenArray aArr(rDocument); | ||||
2168 | aArr.AddOpCode( ocSubTotal ); | ||||
2169 | aArr.AddOpCode( ocOpen ); | ||||
2170 | aArr.AddDouble( static_cast<double>(pResFunc[nResult]) ); | ||||
2171 | aArr.AddOpCode( ocSep ); | ||||
2172 | aArr.AddDoubleReference( aRef ); | ||||
2173 | aArr.AddOpCode( ocClose ); | ||||
2174 | aArr.AddOpCode( ocStop ); | ||||
2175 | ScFormulaCell* pCell = new ScFormulaCell( | ||||
2176 | rDocument, ScAddress(nResCols[nResult], rRowEntry.nDestRow, nTab), aArr); | ||||
2177 | if ( rParam.bIncludePattern ) | ||||
2178 | pCell->SetNeedNumberFormat(true); | ||||
2179 | |||||
2180 | SetFormulaCell(nResCols[nResult], rRowEntry.nDestRow, pCell); | ||||
2181 | if ( nResCols[nResult] != nGroupCol[rRowEntry.nGroupNo] ) | ||||
2182 | { | ||||
2183 | ApplyStyle( nResCols[nResult], rRowEntry.nDestRow, pStyle ); | ||||
2184 | |||||
2185 | lcl_RemoveNumberFormat( this, nResCols[nResult], rRowEntry.nDestRow ); | ||||
2186 | } | ||||
2187 | } | ||||
2188 | |||||
2189 | } | ||||
2190 | |||||
2191 | //TODO: according to setting, shift intermediate-sum rows up? | ||||
2192 | |||||
2193 | //TODO: create Outlines directly? | ||||
2194 | |||||
2195 | if (bSpaceLeft) | ||||
2196 | DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow ); | ||||
2197 | |||||
2198 | rParam.nRow2 = nEndRow; // new end | ||||
2199 | return bSpaceLeft; | ||||
2200 | } | ||||
2201 | |||||
2202 | namespace { | ||||
2203 | |||||
2204 | class QueryEvaluator | ||||
2205 | { | ||||
2206 | ScDocument& mrDoc; | ||||
2207 | svl::SharedStringPool& mrStrPool; | ||||
2208 | const ScTable& mrTab; | ||||
2209 | const ScQueryParam& mrParam; | ||||
2210 | bool mpTestEqualCondition; | ||||
2211 | utl::TransliterationWrapper* mpTransliteration; | ||||
2212 | CollatorWrapper* mpCollator; | ||||
2213 | const bool mbMatchWholeCell; | ||||
2214 | const bool mbCaseSensitive; | ||||
2215 | |||||
2216 | static bool isPartialTextMatchOp(const ScQueryEntry& rEntry) | ||||
2217 | { | ||||
2218 | switch (rEntry.eOp) | ||||
2219 | { | ||||
2220 | // these operators can only be used with textural comparisons. | ||||
2221 | case SC_CONTAINS: | ||||
2222 | case SC_DOES_NOT_CONTAIN: | ||||
2223 | case SC_BEGINS_WITH: | ||||
2224 | case SC_ENDS_WITH: | ||||
2225 | case SC_DOES_NOT_BEGIN_WITH: | ||||
2226 | case SC_DOES_NOT_END_WITH: | ||||
2227 | return true; | ||||
2228 | default: | ||||
2229 | ; | ||||
2230 | } | ||||
2231 | return false; | ||||
2232 | } | ||||
2233 | |||||
2234 | static bool isTextMatchOp(const ScQueryEntry& rEntry) | ||||
2235 | { | ||||
2236 | if (isPartialTextMatchOp(rEntry)) | ||||
2237 | return true; | ||||
2238 | |||||
2239 | switch (rEntry.eOp) | ||||
2240 | { | ||||
2241 | // these operators can be used for either textural or value comparison. | ||||
2242 | case SC_EQUAL: | ||||
2243 | case SC_NOT_EQUAL: | ||||
2244 | return true; | ||||
2245 | default: | ||||
2246 | ; | ||||
2247 | } | ||||
2248 | return false; | ||||
2249 | } | ||||
2250 | |||||
2251 | bool isRealWildOrRegExp(const ScQueryEntry& rEntry) const | ||||
2252 | { | ||||
2253 | if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal) | ||||
2254 | return false; | ||||
2255 | |||||
2256 | return isTextMatchOp(rEntry); | ||||
2257 | } | ||||
2258 | |||||
2259 | bool isTestWildOrRegExp(const ScQueryEntry& rEntry) const | ||||
2260 | { | ||||
2261 | if (!mpTestEqualCondition) | ||||
2262 | return false; | ||||
2263 | |||||
2264 | if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal) | ||||
2265 | return false; | ||||
2266 | |||||
2267 | return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL); | ||||
2268 | } | ||||
2269 | |||||
2270 | void setupTransliteratorIfNeeded() | ||||
2271 | { | ||||
2272 | if (!mpTransliteration) | ||||
2273 | mpTransliteration = mrParam.bCaseSens ? ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration(); | ||||
2274 | } | ||||
2275 | |||||
2276 | void setupCollatorIfNeeded() | ||||
2277 | { | ||||
2278 | if (!mpCollator) | ||||
2279 | mpCollator = mrParam.bCaseSens ? ScGlobal::GetCaseCollator() : ScGlobal::GetCollator(); | ||||
2280 | } | ||||
2281 | |||||
2282 | public: | ||||
2283 | QueryEvaluator(ScDocument& rDoc, const ScTable& rTab, const ScQueryParam& rParam, | ||||
2284 | bool pTestEqualCondition) : | ||||
2285 | mrDoc(rDoc), | ||||
2286 | mrStrPool(rDoc.GetSharedStringPool()), | ||||
2287 | mrTab(rTab), | ||||
2288 | mrParam(rParam), | ||||
2289 | mpTestEqualCondition(pTestEqualCondition), | ||||
2290 | mpTransliteration(nullptr), | ||||
2291 | mpCollator(nullptr), | ||||
2292 | mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell()), | ||||
2293 | mbCaseSensitive( rParam.bCaseSens ) | ||||
2294 | { | ||||
2295 | } | ||||
2296 | |||||
2297 | bool isQueryByValue( | ||||
2298 | const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, ScRefCellValue& rCell) | ||||
2299 | { | ||||
2300 | if (rItem.meType == ScQueryEntry::ByString) | ||||
2301 | return false; | ||||
2302 | |||||
2303 | if (!rCell.isEmpty()) | ||||
2304 | { | ||||
2305 | if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE) | ||||
2306 | // Error values are compared as string. | ||||
2307 | return false; | ||||
2308 | |||||
2309 | return rCell.hasNumeric(); | ||||
2310 | } | ||||
2311 | |||||
2312 | return mrTab.HasValueData(nCol, nRow); | ||||
2313 | } | ||||
2314 | |||||
2315 | bool isQueryByString( | ||||
2316 | const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, | ||||
2317 | SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell) | ||||
2318 | { | ||||
2319 | if (isTextMatchOp(rEntry)) | ||||
2320 | return true; | ||||
2321 | |||||
2322 | if (rItem.meType != ScQueryEntry::ByString) | ||||
2323 | return false; | ||||
2324 | |||||
2325 | if (!rCell.isEmpty()) | ||||
2326 | return rCell.hasString(); | ||||
2327 | |||||
2328 | return mrTab.HasStringData(nCol, nRow); | ||||
2329 | } | ||||
2330 | |||||
2331 | std::pair<bool,bool> compareByValue( | ||||
2332 | const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow, | ||||
2333 | const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, | ||||
2334 | const ScInterpreterContext* pContext) | ||||
2335 | { | ||||
2336 | bool bOk = false; | ||||
2337 | bool bTestEqual = false; | ||||
2338 | double nCellVal; | ||||
2339 | if (!rCell.isEmpty()) | ||||
2340 | { | ||||
2341 | switch (rCell.meType) | ||||
2342 | { | ||||
2343 | case CELLTYPE_VALUE : | ||||
2344 | nCellVal = rCell.mfValue; | ||||
2345 | break; | ||||
2346 | case CELLTYPE_FORMULA : | ||||
2347 | nCellVal = rCell.mpFormula->GetValue(); | ||||
2348 | break; | ||||
2349 | default: | ||||
2350 | nCellVal = 0.0; | ||||
2351 | } | ||||
2352 | |||||
2353 | } | ||||
2354 | else | ||||
2355 | nCellVal = mrTab.GetValue(nCol, nRow); | ||||
2356 | |||||
2357 | /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a | ||||
2358 | * date+time format was queried rEntry.bQueryByDate is not set. In | ||||
2359 | * case other queries wanted to use this mechanism they should do | ||||
2360 | * the same, in other words only if rEntry.nVal is an integer value | ||||
2361 | * rEntry.bQueryByDate should be true and the time fraction be | ||||
2362 | * stripped here. */ | ||||
2363 | if (rItem.meType == ScQueryEntry::ByDate) | ||||
2364 | { | ||||
2365 | sal_uInt32 nNumFmt = pContext ? mrTab.GetNumberFormat(*pContext, ScAddress(nCol, nRow, mrTab.GetTab())) : | ||||
2366 | mrTab.GetNumberFormat(nCol, nRow); | ||||
2367 | SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : mrDoc.GetFormatTable(); | ||||
2368 | const SvNumberformat* pEntry = pFormatter->GetEntry(nNumFmt); | ||||
2369 | if (pEntry) | ||||
2370 | { | ||||
2371 | SvNumFormatType nNumFmtType = pEntry->GetType(); | ||||
2372 | /* NOTE: Omitting the check for absence of | ||||
2373 | * css::util::NumberFormat::TIME would include also date+time formatted | ||||
2374 | * values of the same day. That may be desired in some | ||||
2375 | * cases, querying all time values of a day, but confusing | ||||
2376 | * in other cases. A user can always setup a standard | ||||
2377 | * filter query for x >= date AND x < date+1 */ | ||||
2378 | if ((nNumFmtType & SvNumFormatType::DATE) && !(nNumFmtType & SvNumFormatType::TIME)) | ||||
2379 | { | ||||
2380 | // The format is of date type. Strip off the time | ||||
2381 | // element. | ||||
2382 | nCellVal = ::rtl::math::approxFloor(nCellVal); | ||||
2383 | } | ||||
2384 | } | ||||
2385 | } | ||||
2386 | |||||
2387 | switch (rEntry.eOp) | ||||
2388 | { | ||||
2389 | case SC_EQUAL : | ||||
2390 | bOk = ::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2391 | break; | ||||
2392 | case SC_LESS : | ||||
2393 | bOk = (nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2394 | break; | ||||
2395 | case SC_GREATER : | ||||
2396 | bOk = (nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2397 | break; | ||||
2398 | case SC_LESS_EQUAL : | ||||
2399 | bOk = (nCellVal < rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2400 | if ( bOk && mpTestEqualCondition ) | ||||
2401 | bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2402 | break; | ||||
2403 | case SC_GREATER_EQUAL : | ||||
2404 | bOk = (nCellVal > rItem.mfVal) || ::rtl::math::approxEqual( nCellVal, rItem.mfVal); | ||||
2405 | if ( bOk && mpTestEqualCondition ) | ||||
2406 | bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2407 | break; | ||||
2408 | case SC_NOT_EQUAL : | ||||
2409 | bOk = !::rtl::math::approxEqual(nCellVal, rItem.mfVal); | ||||
2410 | break; | ||||
2411 | default: | ||||
2412 | { | ||||
2413 | // added to avoid warnings | ||||
2414 | } | ||||
2415 | } | ||||
2416 | |||||
2417 | return std::pair<bool,bool>(bOk, bTestEqual); | ||||
2418 | } | ||||
2419 | |||||
2420 | std::pair<bool,bool> compareByString( | ||||
2421 | ScRefCellValue& rCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, | ||||
2422 | const ScInterpreterContext* pContext) | ||||
2423 | { | ||||
2424 | if (!rCell.isEmpty()) | ||||
2425 | { | ||||
2426 | if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE) | ||||
2427 | { | ||||
2428 | // Error cell is evaluated as string (for now). | ||||
2429 | const svl::SharedString aCellStr = mrStrPool.intern(ScGlobal::GetErrorString(rCell.mpFormula->GetErrCode())); | ||||
2430 | return compareByStringComparator(rEntry, rItem, &aCellStr, nullptr); | ||||
2431 | } | ||||
2432 | else if (rCell.meType == CELLTYPE_STRING) | ||||
2433 | { | ||||
2434 | return compareByStringComparator(rEntry, rItem, rCell.mpString, nullptr); | ||||
2435 | } | ||||
2436 | else | ||||
2437 | { | ||||
2438 | sal_uInt32 nFormat = pContext ? mrTab.GetNumberFormat( *pContext, ScAddress(static_cast<SCCOL>(rEntry.nField), nRow, mrTab.GetTab()) ) : | ||||
2439 | mrTab.GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow ); | ||||
2440 | OUString aStr; | ||||
2441 | SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : mrDoc.GetFormatTable(); | ||||
2442 | ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrDoc); | ||||
2443 | return compareByStringComparator(rEntry, rItem, nullptr, &aStr); | ||||
2444 | } | ||||
2445 | } | ||||
2446 | else | ||||
2447 | { | ||||
2448 | OUString aStr; | ||||
2449 | mrTab.GetInputString(static_cast<SCCOL>(rEntry.nField), nRow, aStr); | ||||
2450 | return compareByStringComparator(rEntry, rItem, nullptr, &aStr); | ||||
2451 | } | ||||
2452 | } | ||||
2453 | |||||
2454 | // Called from compareByString() method, where different sources of strings are checked. | ||||
2455 | // The value is placed inside one parameter: [pValueSource1] or [pValueSource2] but never in both. | ||||
2456 | std::pair<bool,bool> compareByStringComparator(const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, | ||||
2457 | const svl::SharedString* pValueSource1, const OUString * pValueSource2) | ||||
2458 | { | ||||
2459 | bool bOk = false; | ||||
2460 | bool bTestEqual = false; | ||||
2461 | bool bMatchWholeCell = mbMatchWholeCell; | ||||
2462 | if (isPartialTextMatchOp(rEntry)) | ||||
2463 | // may have to do partial textural comparison. | ||||
2464 | bMatchWholeCell = false; | ||||
2465 | |||||
2466 | const bool bRealWildOrRegExp = isRealWildOrRegExp(rEntry); | ||||
2467 | const bool bTestWildOrRegExp = isTestWildOrRegExp(rEntry); | ||||
2468 | |||||
2469 | // [pValueSource1] or [pValueSource2] but never both of them or none of them | ||||
2470 | assert((pValueSource1 != nullptr) != (pValueSource2 != nullptr))(static_cast <bool> ((pValueSource1 != nullptr) != (pValueSource2 != nullptr)) ? void (0) : __assert_fail ("(pValueSource1 != nullptr) != (pValueSource2 != nullptr)" , "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 2470, __extension__ __PRETTY_FUNCTION__)); | ||||
2471 | |||||
2472 | if ( bRealWildOrRegExp || bTestWildOrRegExp ) | ||||
2473 | { | ||||
2474 | const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2; | ||||
2475 | |||||
2476 | sal_Int32 nStart = 0; | ||||
2477 | sal_Int32 nEnd = rValue.getLength(); | ||||
2478 | |||||
2479 | // from 614 on, nEnd is behind the found text | ||||
2480 | bool bMatch = false; | ||||
2481 | if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) | ||||
2482 | { | ||||
2483 | nEnd = 0; | ||||
2484 | nStart = rValue.getLength(); | ||||
2485 | bMatch = rEntry.GetSearchTextPtr( mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell ) | ||||
2486 | ->SearchBackward(rValue, &nStart, &nEnd); | ||||
2487 | } | ||||
2488 | else | ||||
2489 | { | ||||
2490 | bMatch = rEntry.GetSearchTextPtr( mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell ) | ||||
2491 | ->SearchForward(rValue, &nStart, &nEnd); | ||||
2492 | } | ||||
2493 | if ( bMatch && bMatchWholeCell | ||||
2494 | && (nStart != 0 || nEnd != rValue.getLength()) ) | ||||
2495 | bMatch = false; // RegExp must match entire cell string | ||||
2496 | if ( bRealWildOrRegExp ) | ||||
2497 | { | ||||
2498 | switch (rEntry.eOp) | ||||
2499 | { | ||||
2500 | case SC_EQUAL: | ||||
2501 | case SC_CONTAINS: | ||||
2502 | bOk = bMatch; | ||||
2503 | break; | ||||
2504 | case SC_NOT_EQUAL: | ||||
2505 | case SC_DOES_NOT_CONTAIN: | ||||
2506 | bOk = !bMatch; | ||||
2507 | break; | ||||
2508 | case SC_BEGINS_WITH: | ||||
2509 | bOk = ( bMatch && (nStart == 0) ); | ||||
2510 | break; | ||||
2511 | case SC_DOES_NOT_BEGIN_WITH: | ||||
2512 | bOk = !( bMatch && (nStart == 0) ); | ||||
2513 | break; | ||||
2514 | case SC_ENDS_WITH: | ||||
2515 | bOk = ( bMatch && (nEnd == rValue.getLength()) ); | ||||
2516 | break; | ||||
2517 | case SC_DOES_NOT_END_WITH: | ||||
2518 | bOk = !( bMatch && (nEnd == rValue.getLength()) ); | ||||
2519 | break; | ||||
2520 | default: | ||||
2521 | { | ||||
2522 | // added to avoid warnings | ||||
2523 | } | ||||
2524 | } | ||||
2525 | } | ||||
2526 | else | ||||
2527 | bTestEqual = bMatch; | ||||
2528 | } | ||||
2529 | if ( !bRealWildOrRegExp ) | ||||
2530 | { | ||||
2531 | // Simple string matching i.e. no regexp match. | ||||
2532 | if (isTextMatchOp(rEntry)) | ||||
2533 | { | ||||
2534 | if (rItem.meType != ScQueryEntry::ByString && rItem.maString.isEmpty()) | ||||
2535 | { | ||||
2536 | // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup), | ||||
2537 | // the query value is assigned directly, and the string is empty. In that case, | ||||
2538 | // don't find any string (isEqual would find empty string results in formula cells). | ||||
2539 | bOk = false; | ||||
2540 | if ( rEntry.eOp == SC_NOT_EQUAL ) | ||||
2541 | bOk = !bOk; | ||||
2542 | } | ||||
2543 | else if ( bMatchWholeCell ) | ||||
2544 | { | ||||
2545 | if (pValueSource1) | ||||
2546 | { | ||||
2547 | // Fast string equality check by comparing string identifiers. | ||||
2548 | if (mrParam.bCaseSens) | ||||
2549 | { | ||||
2550 | bOk = pValueSource1->getData() == rItem.maString.getData(); | ||||
2551 | } | ||||
2552 | else | ||||
2553 | { | ||||
2554 | bOk = pValueSource1->getDataIgnoreCase() == rItem.maString.getDataIgnoreCase(); | ||||
2555 | } | ||||
2556 | } | ||||
2557 | else // if (pValueSource2) | ||||
2558 | { | ||||
2559 | if (mrParam.bCaseSens) | ||||
2560 | { | ||||
2561 | bOk = (*pValueSource2 == rItem.maString.getString()); | ||||
2562 | } | ||||
2563 | else | ||||
2564 | { | ||||
2565 | // fallback | ||||
2566 | const svl::SharedString rSource2(mrStrPool.intern(*pValueSource2)); | ||||
2567 | // Fast string equality check by comparing string identifiers. | ||||
2568 | bOk = rSource2.getDataIgnoreCase() == rItem.maString.getDataIgnoreCase(); | ||||
2569 | } | ||||
2570 | } | ||||
2571 | |||||
2572 | if ( rEntry.eOp == SC_NOT_EQUAL ) | ||||
2573 | bOk = !bOk; | ||||
2574 | } | ||||
2575 | else | ||||
2576 | { | ||||
2577 | // Where do we find a match (if at all) | ||||
2578 | sal_Int32 nStrPos; | ||||
2579 | |||||
2580 | if (!mbCaseSensitive) | ||||
2581 | { // Common case for vlookup etc. | ||||
2582 | const svl::SharedString rSource(pValueSource1? *pValueSource1 : mrStrPool.intern(*pValueSource2)); | ||||
2583 | |||||
2584 | const rtl_uString *pQuer = rItem.maString.getDataIgnoreCase(); | ||||
2585 | const rtl_uString *pCellStr = rSource.getDataIgnoreCase(); | ||||
2586 | |||||
2587 | assert(pQuer != nullptr)(static_cast <bool> (pQuer != nullptr) ? void (0) : __assert_fail ("pQuer != nullptr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 2587, __extension__ __PRETTY_FUNCTION__)); | ||||
2588 | assert(pCellStr != nullptr)(static_cast <bool> (pCellStr != nullptr) ? void (0) : __assert_fail ("pCellStr != nullptr", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 2588, __extension__ __PRETTY_FUNCTION__)); | ||||
2589 | |||||
2590 | const sal_Int32 nIndex = (rEntry.eOp == SC_ENDS_WITH || | ||||
2591 | rEntry.eOp == SC_DOES_NOT_END_WITH) ? | ||||
2592 | (pCellStr->length - pQuer->length) : 0; | ||||
2593 | |||||
2594 | if (nIndex < 0) | ||||
2595 | nStrPos = -1; | ||||
2596 | else if (rEntry.eOp == SC_EQUAL || | ||||
2597 | rEntry.eOp == SC_NOT_EQUAL) | ||||
2598 | { | ||||
2599 | nStrPos = pCellStr == pQuer ? 0 : -1; | ||||
2600 | } | ||||
2601 | else | ||||
2602 | { // OUString::indexOf | ||||
2603 | nStrPos = rtl_ustr_indexOfStr_WithLength( | ||||
2604 | pCellStr->buffer + nIndex, pCellStr->length - nIndex, | ||||
2605 | pQuer->buffer, pQuer->length ); | ||||
2606 | |||||
2607 | if (nStrPos >= 0) | ||||
2608 | nStrPos += nIndex; | ||||
2609 | } | ||||
2610 | } | ||||
2611 | else | ||||
2612 | { | ||||
2613 | const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2; | ||||
2614 | const OUString aQueryStr = rItem.maString.getString(); | ||||
2615 | const LanguageType nLang = ScGlobal::xSysLocale->GetLanguageTag().getLanguageType(); | ||||
2616 | setupTransliteratorIfNeeded(); | ||||
2617 | const OUString aCell( mpTransliteration->transliterate( | ||||
2618 | rValue, nLang, 0, rValue.getLength(), | ||||
2619 | nullptr ) ); | ||||
2620 | |||||
2621 | const OUString aQuer( mpTransliteration->transliterate( | ||||
2622 | aQueryStr, nLang, 0, aQueryStr.getLength(), | ||||
2623 | nullptr ) ); | ||||
2624 | |||||
2625 | const sal_Int32 nIndex = (rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH) ? | ||||
2626 | (aCell.getLength() - aQuer.getLength()) : 0; | ||||
2627 | nStrPos = ((nIndex < 0) ? -1 : aCell.indexOf( aQuer, nIndex )); | ||||
2628 | } | ||||
2629 | switch (rEntry.eOp) | ||||
2630 | { | ||||
2631 | case SC_EQUAL: | ||||
2632 | bOk = ( nStrPos == 0 ); | ||||
2633 | break; | ||||
2634 | case SC_CONTAINS: | ||||
2635 | bOk = ( nStrPos != -1 ); | ||||
2636 | break; | ||||
2637 | case SC_NOT_EQUAL: | ||||
2638 | bOk = ( nStrPos != 0 ); | ||||
2639 | break; | ||||
2640 | case SC_DOES_NOT_CONTAIN: | ||||
2641 | bOk = ( nStrPos == -1 ); | ||||
2642 | break; | ||||
2643 | case SC_BEGINS_WITH: | ||||
2644 | bOk = ( nStrPos == 0 ); | ||||
2645 | break; | ||||
2646 | case SC_DOES_NOT_BEGIN_WITH: | ||||
2647 | bOk = ( nStrPos != 0 ); | ||||
2648 | break; | ||||
2649 | case SC_ENDS_WITH: | ||||
2650 | bOk = ( nStrPos >= 0 ); | ||||
2651 | break; | ||||
2652 | case SC_DOES_NOT_END_WITH: | ||||
2653 | bOk = ( nStrPos < 0 ); | ||||
2654 | break; | ||||
2655 | default: | ||||
2656 | { | ||||
2657 | // added to avoid warnings | ||||
2658 | } | ||||
2659 | } | ||||
2660 | } | ||||
2661 | } | ||||
2662 | else | ||||
2663 | { // use collator here because data was probably sorted | ||||
2664 | const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2; | ||||
2665 | setupCollatorIfNeeded(); | ||||
2666 | sal_Int32 nCompare = mpCollator->compareString( | ||||
2667 | rValue, rItem.maString.getString()); | ||||
2668 | switch (rEntry.eOp) | ||||
2669 | { | ||||
2670 | case SC_LESS : | ||||
2671 | bOk = (nCompare < 0); | ||||
2672 | break; | ||||
2673 | case SC_GREATER : | ||||
2674 | bOk = (nCompare > 0); | ||||
2675 | break; | ||||
2676 | case SC_LESS_EQUAL : | ||||
2677 | bOk = (nCompare <= 0); | ||||
2678 | if ( bOk && mpTestEqualCondition && !bTestEqual ) | ||||
2679 | bTestEqual = (nCompare == 0); | ||||
2680 | break; | ||||
2681 | case SC_GREATER_EQUAL : | ||||
2682 | bOk = (nCompare >= 0); | ||||
2683 | if ( bOk && mpTestEqualCondition && !bTestEqual ) | ||||
2684 | bTestEqual = (nCompare == 0); | ||||
2685 | break; | ||||
2686 | default: | ||||
2687 | { | ||||
2688 | // added to avoid warnings | ||||
2689 | } | ||||
2690 | } | ||||
2691 | } | ||||
2692 | } | ||||
2693 | |||||
2694 | return std::pair<bool,bool>(bOk, bTestEqual); | ||||
2695 | } | ||||
2696 | |||||
2697 | // To be called only if both isQueryByValue() and isQueryByString() | ||||
2698 | // returned false and range lookup is wanted! In range lookup comparison | ||||
2699 | // numbers are less than strings. Nothing else is compared. | ||||
2700 | std::pair<bool,bool> compareByRangeLookup( | ||||
2701 | const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow, | ||||
2702 | const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem) | ||||
2703 | { | ||||
2704 | bool bTestEqual = false; | ||||
2705 | |||||
2706 | if (rItem.meType == ScQueryEntry::ByString && rEntry.eOp != SC_LESS && rEntry.eOp != SC_LESS_EQUAL) | ||||
2707 | return std::pair<bool,bool>(false, bTestEqual); | ||||
2708 | |||||
2709 | if (rItem.meType != ScQueryEntry::ByString && rEntry.eOp != SC_GREATER && rEntry.eOp != SC_GREATER_EQUAL) | ||||
2710 | return std::pair<bool,bool>(false, bTestEqual); | ||||
2711 | |||||
2712 | if (!rCell.isEmpty()) | ||||
2713 | { | ||||
2714 | if (rItem.meType == ScQueryEntry::ByString) | ||||
2715 | { | ||||
2716 | if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE) | ||||
2717 | // Error values are compared as string. | ||||
2718 | return std::pair<bool,bool>(false, bTestEqual); | ||||
2719 | |||||
2720 | return std::pair<bool,bool>(rCell.hasNumeric(), bTestEqual); | ||||
2721 | } | ||||
2722 | |||||
2723 | return std::pair<bool,bool>(!rCell.hasNumeric(), bTestEqual); | ||||
2724 | } | ||||
2725 | |||||
2726 | if (rItem.meType == ScQueryEntry::ByString) | ||||
2727 | return std::pair<bool,bool>(mrTab.HasValueData(nCol, nRow), bTestEqual); | ||||
2728 | |||||
2729 | return std::pair<bool,bool>(!mrTab.HasValueData(nCol, nRow), bTestEqual); | ||||
2730 | } | ||||
2731 | }; | ||||
2732 | |||||
2733 | } | ||||
2734 | |||||
2735 | bool ScTable::ValidQuery( | ||||
2736 | SCROW nRow, const ScQueryParam& rParam, const ScRefCellValue* pCell, bool* pbTestEqualCondition, | ||||
2737 | const ScInterpreterContext* pContext, sc::TableColumnBlockPositionSet* pBlockPos) | ||||
2738 | { | ||||
2739 | if (!rParam.GetEntry(0).bDoQuery) | ||||
2740 | return true; | ||||
2741 | |||||
2742 | //--------------------------------------------------------------- | ||||
2743 | |||||
2744 | const SCSIZE nFixedBools = 32; | ||||
2745 | bool aBool[nFixedBools]; | ||||
2746 | bool aTest[nFixedBools]; | ||||
2747 | SCSIZE nEntryCount = rParam.GetEntryCount(); | ||||
2748 | bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new bool[nEntryCount] ); | ||||
2749 | bool* pTest = ( nEntryCount
| ||||
2750 | |||||
2751 | long nPos = -1; | ||||
2752 | QueryEvaluator aEval(rDocument, *this, rParam, pbTestEqualCondition != nullptr); | ||||
2753 | ScQueryParam::const_iterator it, itBeg = rParam.begin(), itEnd = rParam.end(); | ||||
2754 | for (it = itBeg; it != itEnd && (*it)->bDoQuery; ++it) | ||||
2755 | { | ||||
2756 | const ScQueryEntry& rEntry = **it; | ||||
2757 | SCCOL nCol = static_cast<SCCOL>(rEntry.nField); | ||||
2758 | |||||
2759 | // We can only handle one single direct query passed as a known pCell, | ||||
2760 | // subsequent queries have to obtain the cell. | ||||
2761 | ScRefCellValue aCell; | ||||
2762 | if(pCell && it == itBeg) | ||||
2763 | aCell = *pCell; | ||||
2764 | else if( pBlockPos ) | ||||
2765 | { // hinted mdds access | ||||
2766 | ScColumn* column = FetchColumn(nCol); | ||||
2767 | aCell = column->GetCellValue(*pBlockPos->getBlockPosition( nCol ), nRow); | ||||
2768 | } | ||||
2769 | else | ||||
2770 | aCell = GetCellValue(nCol, nRow); | ||||
2771 | |||||
2772 | std::pair<bool,bool> aRes(false, false); | ||||
2773 | |||||
2774 | const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); | ||||
2775 | if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty) | ||||
2776 | { | ||||
2777 | bool hasData; | ||||
2778 | if( pBlockPos ) | ||||
2779 | { | ||||
2780 | ScColumn* column = FetchColumn(rEntry.nField); | ||||
2781 | hasData = column->HasDataAt(*pBlockPos->getBlockPosition(rEntry.nField), nRow); | ||||
2782 | } | ||||
2783 | else | ||||
2784 | hasData = aCol[rEntry.nField].HasDataAt(nRow); | ||||
2785 | if (rEntry.IsQueryByEmpty()) | ||||
2786 | aRes.first = !hasData; | ||||
2787 | else | ||||
2788 | { | ||||
2789 | assert(rEntry.IsQueryByNonEmpty())(static_cast <bool> (rEntry.IsQueryByNonEmpty()) ? void (0) : __assert_fail ("rEntry.IsQueryByNonEmpty()", "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 2789, __extension__ __PRETTY_FUNCTION__)); | ||||
2790 | aRes.first = hasData; | ||||
2791 | } | ||||
2792 | } | ||||
2793 | else | ||||
2794 | { | ||||
2795 | for (const auto& rItem : rItems) | ||||
2796 | { | ||||
2797 | if (aEval.isQueryByValue(rItem, nCol, nRow, aCell)) | ||||
2798 | { | ||||
2799 | std::pair<bool,bool> aThisRes = | ||||
2800 | aEval.compareByValue(aCell, nCol, nRow, rEntry, rItem, pContext); | ||||
2801 | aRes.first |= aThisRes.first; | ||||
2802 | aRes.second |= aThisRes.second; | ||||
2803 | } | ||||
2804 | else if (aEval.isQueryByString(rEntry, rItem, nCol, nRow, aCell)) | ||||
2805 | { | ||||
2806 | std::pair<bool,bool> aThisRes = | ||||
2807 | aEval.compareByString(aCell, nRow, rEntry, rItem, pContext); | ||||
2808 | aRes.first |= aThisRes.first; | ||||
2809 | aRes.second |= aThisRes.second; | ||||
2810 | } | ||||
2811 | else if (rParam.mbRangeLookup) | ||||
2812 | { | ||||
2813 | std::pair<bool,bool> aThisRes = | ||||
2814 | aEval.compareByRangeLookup(aCell, nCol, nRow, rEntry, rItem); | ||||
2815 | aRes.first |= aThisRes.first; | ||||
2816 | aRes.second |= aThisRes.second; | ||||
2817 | } | ||||
2818 | |||||
2819 | if (aRes.first && aRes.second) | ||||
2820 | break; | ||||
2821 | } | ||||
2822 | } | ||||
2823 | |||||
2824 | if (nPos == -1) | ||||
2825 | { | ||||
2826 | nPos++; | ||||
2827 | pPasst[nPos] = aRes.first; | ||||
2828 | pTest[nPos] = aRes.second; | ||||
2829 | } | ||||
2830 | else | ||||
2831 | { | ||||
2832 | if (rEntry.eConnect == SC_AND) | ||||
2833 | { | ||||
2834 | pPasst[nPos] = pPasst[nPos] && aRes.first; | ||||
2835 | pTest[nPos] = pTest[nPos] && aRes.second; | ||||
2836 | } | ||||
2837 | else | ||||
2838 | { | ||||
2839 | nPos++; | ||||
2840 | pPasst[nPos] = aRes.first; | ||||
2841 | pTest[nPos] = aRes.second; | ||||
2842 | } | ||||
2843 | } | ||||
2844 | } | ||||
2845 | |||||
2846 | for ( long j=1; j <= nPos; j++ ) | ||||
2847 | { | ||||
2848 | pPasst[0] = pPasst[0] || pPasst[j]; | ||||
2849 | pTest[0] = pTest[0] || pTest[j]; | ||||
2850 | } | ||||
2851 | |||||
2852 | bool bRet = pPasst[0]; | ||||
| |||||
2853 | if ( pPasst != &aBool[0] ) | ||||
2854 | delete [] pPasst; | ||||
2855 | if ( pbTestEqualCondition ) | ||||
2856 | *pbTestEqualCondition = pTest[0]; | ||||
2857 | if ( pTest != &aTest[0] ) | ||||
2858 | delete [] pTest; | ||||
2859 | |||||
2860 | return bRet; | ||||
2861 | } | ||||
2862 | |||||
2863 | void ScTable::TopTenQuery( ScQueryParam& rParam ) | ||||
2864 | { | ||||
2865 | bool bSortCollatorInitialized = false; | ||||
2866 | SCSIZE nEntryCount = rParam.GetEntryCount(); | ||||
2867 | SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1); | ||||
2868 | SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1); | ||||
2869 | for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ ) | ||||
2870 | { | ||||
2871 | ScQueryEntry& rEntry = rParam.GetEntry(i); | ||||
2872 | ScQueryEntry::Item& rItem = rEntry.GetQueryItem(); | ||||
2873 | |||||
2874 | switch ( rEntry.eOp ) | ||||
2875 | { | ||||
2876 | case SC_TOPVAL: | ||||
2877 | case SC_BOTVAL: | ||||
2878 | case SC_TOPPERC: | ||||
2879 | case SC_BOTPERC: | ||||
2880 | { | ||||
2881 | ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) ); | ||||
2882 | aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare | ||||
2883 | if ( !bSortCollatorInitialized ) | ||||
2884 | { | ||||
2885 | bSortCollatorInitialized = true; | ||||
2886 | InitSortCollator( aLocalSortParam ); | ||||
2887 | } | ||||
2888 | std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery, false)); | ||||
2889 | DecoladeRow( pArray.get(), nRow1, rParam.nRow2 ); | ||||
2890 | QuickSort( pArray.get(), nRow1, rParam.nRow2 ); | ||||
2891 | std::unique_ptr<ScSortInfo[]> const & ppInfo = pArray->GetFirstArray(); | ||||
2892 | SCSIZE nValidCount = nCount; | ||||
2893 | // Don't count note or blank cells, they are sorted to the end | ||||
2894 | while (nValidCount > 0 && ppInfo[nValidCount-1].maCell.isEmpty()) | ||||
2895 | nValidCount--; | ||||
2896 | // Don't count Strings, they are between Value and blank | ||||
2897 | while (nValidCount > 0 && ppInfo[nValidCount-1].maCell.hasString()) | ||||
2898 | nValidCount--; | ||||
2899 | if ( nValidCount > 0 ) | ||||
2900 | { | ||||
2901 | if ( rItem.meType == ScQueryEntry::ByString ) | ||||
2902 | { // by string ain't going to work | ||||
2903 | rItem.meType = ScQueryEntry::ByValue; | ||||
2904 | rItem.mfVal = 10; // 10 and 10% respectively | ||||
2905 | } | ||||
2906 | SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1); | ||||
2907 | SCSIZE nOffset = 0; | ||||
2908 | switch ( rEntry.eOp ) | ||||
2909 | { | ||||
2910 | case SC_TOPVAL: | ||||
2911 | { | ||||
2912 | rEntry.eOp = SC_GREATER_EQUAL; | ||||
2913 | if ( nVal > nValidCount ) | ||||
2914 | nVal = nValidCount; | ||||
2915 | nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount | ||||
2916 | } | ||||
2917 | break; | ||||
2918 | case SC_BOTVAL: | ||||
2919 | { | ||||
2920 | rEntry.eOp = SC_LESS_EQUAL; | ||||
2921 | if ( nVal > nValidCount ) | ||||
2922 | nVal = nValidCount; | ||||
2923 | nOffset = nVal - 1; // 1 <= nVal <= nValidCount | ||||
2924 | } | ||||
2925 | break; | ||||
2926 | case SC_TOPPERC: | ||||
2927 | { | ||||
2928 | rEntry.eOp = SC_GREATER_EQUAL; | ||||
2929 | if ( nVal > 100 ) | ||||
2930 | nVal = 100; | ||||
2931 | nOffset = nValidCount - (nValidCount * nVal / 100); | ||||
2932 | if ( nOffset >= nValidCount ) | ||||
2933 | nOffset = nValidCount - 1; | ||||
2934 | } | ||||
2935 | break; | ||||
2936 | case SC_BOTPERC: | ||||
2937 | { | ||||
2938 | rEntry.eOp = SC_LESS_EQUAL; | ||||
2939 | if ( nVal > 100 ) | ||||
2940 | nVal = 100; | ||||
2941 | nOffset = (nValidCount * nVal / 100); | ||||
2942 | if ( nOffset >= nValidCount ) | ||||
2943 | nOffset = nValidCount - 1; | ||||
2944 | } | ||||
2945 | break; | ||||
2946 | default: | ||||
2947 | { | ||||
2948 | // added to avoid warnings | ||||
2949 | } | ||||
2950 | } | ||||
2951 | ScRefCellValue aCell = ppInfo[nOffset].maCell; | ||||
2952 | if (aCell.hasNumeric()) | ||||
2953 | rItem.mfVal = aCell.getValue(); | ||||
2954 | else | ||||
2955 | { | ||||
2956 | OSL_FAIL( "TopTenQuery: pCell no ValueData" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "2956" ": "), "%s", "TopTenQuery: pCell no ValueData"); } } while (false); | ||||
2957 | rEntry.eOp = SC_GREATER_EQUAL; | ||||
2958 | rItem.mfVal = 0; | ||||
2959 | } | ||||
2960 | } | ||||
2961 | else | ||||
2962 | { | ||||
2963 | rEntry.eOp = SC_GREATER_EQUAL; | ||||
2964 | rItem.meType = ScQueryEntry::ByValue; | ||||
2965 | rItem.mfVal = 0; | ||||
2966 | } | ||||
2967 | } | ||||
2968 | break; | ||||
2969 | default: | ||||
2970 | { | ||||
2971 | // added to avoid warnings | ||||
2972 | } | ||||
2973 | } | ||||
2974 | } | ||||
2975 | if ( bSortCollatorInitialized ) | ||||
2976 | DestroySortCollator(); | ||||
2977 | } | ||||
2978 | |||||
2979 | namespace { | ||||
2980 | |||||
2981 | class PrepareQueryItem | ||||
2982 | { | ||||
2983 | const ScDocument& mrDoc; | ||||
2984 | public: | ||||
2985 | explicit PrepareQueryItem(const ScDocument& rDoc) : mrDoc(rDoc) {} | ||||
2986 | |||||
2987 | void operator() (ScQueryEntry::Item& rItem) | ||||
2988 | { | ||||
2989 | // Double-check if the query by date is really appropriate. | ||||
2990 | |||||
2991 | if (rItem.meType != ScQueryEntry::ByDate) | ||||
2992 | return; | ||||
2993 | |||||
2994 | sal_uInt32 nIndex = 0; | ||||
2995 | bool bNumber = mrDoc.GetFormatTable()-> | ||||
2996 | IsNumberFormat(rItem.maString.getString(), nIndex, rItem.mfVal); | ||||
2997 | |||||
2998 | if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET10000) != 0)) | ||||
2999 | { | ||||
3000 | const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex); | ||||
3001 | if (pEntry) | ||||
3002 | { | ||||
3003 | SvNumFormatType nNumFmtType = pEntry->GetType(); | ||||
3004 | if (!(nNumFmtType & SvNumFormatType::DATE) || (nNumFmtType & SvNumFormatType::TIME)) | ||||
3005 | rItem.meType = ScQueryEntry::ByValue; // not a date only | ||||
3006 | } | ||||
3007 | else | ||||
3008 | rItem.meType = ScQueryEntry::ByValue; // what the ... not a date | ||||
3009 | } | ||||
3010 | else | ||||
3011 | rItem.meType = ScQueryEntry::ByValue; // not a date | ||||
3012 | } | ||||
3013 | }; | ||||
3014 | |||||
3015 | void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam ) | ||||
3016 | { | ||||
3017 | bool bTopTen = false; | ||||
3018 | SCSIZE nEntryCount = rParam.GetEntryCount(); | ||||
3019 | |||||
3020 | for ( SCSIZE i = 0; i < nEntryCount; ++i ) | ||||
3021 | { | ||||
3022 | ScQueryEntry& rEntry = rParam.GetEntry(i); | ||||
3023 | if (!rEntry.bDoQuery) | ||||
3024 | continue; | ||||
3025 | |||||
3026 | ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); | ||||
3027 | std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc)); | ||||
3028 | |||||
3029 | if ( !bTopTen ) | ||||
3030 | { | ||||
3031 | switch ( rEntry.eOp ) | ||||
3032 | { | ||||
3033 | case SC_TOPVAL: | ||||
3034 | case SC_BOTVAL: | ||||
3035 | case SC_TOPPERC: | ||||
3036 | case SC_BOTPERC: | ||||
3037 | { | ||||
3038 | bTopTen = true; | ||||
3039 | } | ||||
3040 | break; | ||||
3041 | default: | ||||
3042 | { | ||||
3043 | } | ||||
3044 | } | ||||
3045 | } | ||||
3046 | } | ||||
3047 | |||||
3048 | if ( bTopTen ) | ||||
3049 | { | ||||
3050 | pTab->TopTenQuery( rParam ); | ||||
3051 | } | ||||
3052 | } | ||||
3053 | |||||
3054 | } | ||||
3055 | |||||
3056 | SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub) | ||||
3057 | { | ||||
3058 | ScQueryParam aParam( rParamOrg ); | ||||
3059 | typedef std::unordered_set<OUString> StrSetType; | ||||
3060 | StrSetType aStrSet; | ||||
3061 | |||||
3062 | bool bStarted = false; | ||||
3063 | bool bOldResult = true; | ||||
3064 | SCROW nOldStart = 0; | ||||
3065 | SCROW nOldEnd = 0; | ||||
3066 | |||||
3067 | SCSIZE nCount = 0; | ||||
3068 | SCROW nOutRow = 0; | ||||
3069 | SCROW nHeader = aParam.bHasHeader ? 1 : 0; | ||||
3070 | |||||
3071 | lcl_PrepareQuery(&rDocument, this, aParam); | ||||
3072 | |||||
3073 | if (!aParam.bInplace) | ||||
3074 | { | ||||
3075 | nOutRow = aParam.nDestRow + nHeader; | ||||
3076 | if (nHeader > 0) | ||||
3077 | CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1, | ||||
3078 | aParam.nDestCol, aParam.nDestRow, aParam.nDestTab ); | ||||
3079 | } | ||||
3080 | |||||
3081 | sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access | ||||
3082 | |||||
3083 | SCROW nRealRow2 = aParam.nRow2; | ||||
3084 | for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j) | ||||
3085 | { | ||||
3086 | bool bResult; // Filter result | ||||
3087 | bool bValid = ValidQuery(j, aParam, nullptr, nullptr, nullptr, &blockPos); | ||||
3088 | if (!bValid && bKeepSub) // Keep subtotals | ||||
3089 | { | ||||
3090 | for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++) | ||||
3091 | { | ||||
3092 | ScRefCellValue aCell = GetCellValue(nCol, j); | ||||
3093 | if (aCell.meType != CELLTYPE_FORMULA) | ||||
3094 | continue; | ||||
3095 | |||||
3096 | if (!aCell.mpFormula->IsSubTotal()) | ||||
3097 | continue; | ||||
3098 | |||||
3099 | if (RefVisible(aCell.mpFormula)) | ||||
3100 | bValid = true; | ||||
3101 | } | ||||
3102 | } | ||||
3103 | if (bValid) | ||||
3104 | { | ||||
3105 | if (aParam.bDuplicate) | ||||
3106 | bResult = true; | ||||
3107 | else | ||||
3108 | { | ||||
3109 | OUStringBuffer aStr; | ||||
3110 | for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++) | ||||
3111 | { | ||||
3112 | OUString aCellStr; | ||||
3113 | GetString(k, j, aCellStr); | ||||
3114 | aStr.append(aCellStr + u"\x0001"); | ||||
3115 | } | ||||
3116 | |||||
3117 | bResult = aStrSet.insert(aStr.makeStringAndClear()).second; // unique if inserted. | ||||
3118 | } | ||||
3119 | } | ||||
3120 | else | ||||
3121 | bResult = false; | ||||
3122 | |||||
3123 | if (aParam.bInplace) | ||||
3124 | { | ||||
3125 | if (bResult == bOldResult && bStarted) | ||||
3126 | nOldEnd = j; | ||||
3127 | else | ||||
3128 | { | ||||
3129 | if (bStarted) | ||||
3130 | DBShowRows(nOldStart,nOldEnd, bOldResult); | ||||
3131 | nOldStart = nOldEnd = j; | ||||
3132 | bOldResult = bResult; | ||||
3133 | } | ||||
3134 | bStarted = true; | ||||
3135 | } | ||||
3136 | else | ||||
3137 | { | ||||
3138 | if (bResult) | ||||
3139 | { | ||||
3140 | CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab ); | ||||
3141 | if( nTab == aParam.nDestTab ) // copy to self, changes may invalidate caching position hints | ||||
3142 | blockPos.invalidate(); | ||||
3143 | ++nOutRow; | ||||
3144 | } | ||||
3145 | } | ||||
3146 | if (bResult) | ||||
3147 | ++nCount; | ||||
3148 | } | ||||
3149 | |||||
3150 | if (aParam.bInplace && bStarted) | ||||
3151 | DBShowRows(nOldStart,nOldEnd, bOldResult); | ||||
3152 | |||||
3153 | if (aParam.bInplace) | ||||
3154 | SetDrawPageSize(); | ||||
3155 | |||||
3156 | return nCount; | ||||
3157 | } | ||||
3158 | |||||
3159 | bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) | ||||
3160 | { | ||||
3161 | bool bValid = true; | ||||
3162 | std::unique_ptr<SCCOL[]> pFields(new SCCOL[nCol2-nCol1+1]); | ||||
3163 | OUString aCellStr; | ||||
3164 | SCCOL nCol = nCol1; | ||||
3165 | OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" )do { if (true && (!(rQueryParam.nTab != SCTAB_MAX))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "3165" ": "), "%s", "rQueryParam.nTab no value, not bad but no good" ); } } while (false); | ||||
3166 | SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab); | ||||
3167 | SCROW nDBRow1 = rQueryParam.nRow1; | ||||
3168 | SCCOL nDBCol2 = rQueryParam.nCol2; | ||||
3169 | // First row must be column headers | ||||
3170 | while (bValid && (nCol <= nCol2)) | ||||
3171 | { | ||||
3172 | OUString aQueryStr; | ||||
3173 | GetUpperCellString(nCol, nRow1, aQueryStr); | ||||
3174 | bool bFound = false; | ||||
3175 | SCCOL i = rQueryParam.nCol1; | ||||
3176 | while (!bFound && (i <= nDBCol2)) | ||||
3177 | { | ||||
3178 | if ( nTab == nDBTab ) | ||||
3179 | GetUpperCellString(i, nDBRow1, aCellStr); | ||||
3180 | else | ||||
3181 | rDocument.GetUpperCellString(i, nDBRow1, nDBTab, aCellStr); | ||||
3182 | bFound = (aCellStr == aQueryStr); | ||||
3183 | if (!bFound) i++; | ||||
3184 | } | ||||
3185 | if (bFound) | ||||
3186 | pFields[nCol - nCol1] = i; | ||||
3187 | else | ||||
3188 | bValid = false; | ||||
3189 | nCol++; | ||||
3190 | } | ||||
3191 | if (bValid) | ||||
3192 | { | ||||
3193 | sal_uLong nVisible = 0; | ||||
3194 | for ( nCol=nCol1; nCol<=nCol2; nCol++ ) | ||||
3195 | nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 ); | ||||
3196 | |||||
3197 | if ( nVisible > SCSIZE_MAX / sizeof(void*) ) | ||||
3198 | { | ||||
3199 | OSL_FAIL("too many filter criteria")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "3199" ": "), "%s", "too many filter criteria"); } } while (false); | ||||
3200 | nVisible = 0; | ||||
3201 | } | ||||
3202 | |||||
3203 | SCSIZE nNewEntries = nVisible; | ||||
3204 | rQueryParam.Resize( nNewEntries ); | ||||
3205 | |||||
3206 | SCSIZE nIndex = 0; | ||||
3207 | SCROW nRow = nRow1 + 1; | ||||
3208 | svl::SharedStringPool& rPool = rDocument.GetSharedStringPool(); | ||||
3209 | while (nRow <= nRow2) | ||||
3210 | { | ||||
3211 | nCol = nCol1; | ||||
3212 | while (nCol <= nCol2) | ||||
3213 | { | ||||
3214 | GetInputString( nCol, nRow, aCellStr ); | ||||
3215 | if (!aCellStr.isEmpty()) | ||||
3216 | { | ||||
3217 | if (nIndex < nNewEntries) | ||||
3218 | { | ||||
3219 | rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1]; | ||||
3220 | rQueryParam.FillInExcelSyntax(rPool, aCellStr, nIndex, nullptr); | ||||
3221 | nIndex++; | ||||
3222 | if (nIndex < nNewEntries) | ||||
3223 | rQueryParam.GetEntry(nIndex).eConnect = SC_AND; | ||||
3224 | } | ||||
3225 | else | ||||
3226 | bValid = false; | ||||
3227 | } | ||||
3228 | nCol++; | ||||
3229 | } | ||||
3230 | nRow++; | ||||
3231 | if (nIndex < nNewEntries) | ||||
3232 | rQueryParam.GetEntry(nIndex).eConnect = SC_OR; | ||||
3233 | } | ||||
3234 | } | ||||
3235 | return bValid; | ||||
3236 | } | ||||
3237 | |||||
3238 | bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) | ||||
3239 | { | ||||
3240 | // A valid StarQuery must be at least 4 columns wide. To be precise it | ||||
3241 | // should be exactly 4 columns ... | ||||
3242 | // Additionally, if this wasn't checked, a formula pointing to a valid 1-3 | ||||
3243 | // column Excel style query range immediately left to itself would result | ||||
3244 | // in a circular reference when the field name or operator or value (first | ||||
3245 | // to third query range column) is obtained (#i58354#). Furthermore, if the | ||||
3246 | // range wasn't sufficiently specified data changes wouldn't flag formula | ||||
3247 | // cells for recalculation. | ||||
3248 | if (nCol2 - nCol1 < 3) | ||||
3249 | return false; | ||||
3250 | |||||
3251 | bool bValid; | ||||
3252 | OUString aCellStr; | ||||
3253 | SCSIZE nIndex = 0; | ||||
3254 | SCROW nRow = nRow1; | ||||
3255 | OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" )do { if (true && (!(rQueryParam.nTab != SCTAB_MAX))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" ":" "3255" ": "), "%s", "rQueryParam.nTab no value, not bad but no good" ); } } while (false); | ||||
3256 | SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab); | ||||
3257 | SCROW nDBRow1 = rQueryParam.nRow1; | ||||
3258 | SCCOL nDBCol2 = rQueryParam.nCol2; | ||||
3259 | |||||
3260 | SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1); | ||||
3261 | rQueryParam.Resize( nNewEntries ); | ||||
3262 | svl::SharedStringPool& rPool = rDocument.GetSharedStringPool(); | ||||
3263 | |||||
3264 | do | ||||
3265 | { | ||||
3266 | ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex); | ||||
3267 | |||||
3268 | bValid = false; | ||||
3269 | // First column AND/OR | ||||
3270 | if (nIndex > 0) | ||||
3271 | { | ||||
3272 | GetUpperCellString(nCol1, nRow, aCellStr); | ||||
3273 | if ( aCellStr == ScResId(STR_TABLE_ANDreinterpret_cast<char const *>("STR_TABLE_AND" "\004" u8"AND" )) ) | ||||
3274 | { | ||||
3275 | rEntry.eConnect = SC_AND; | ||||
3276 | bValid = true; | ||||
3277 | } | ||||
3278 | else if ( aCellStr == ScResId(STR_TABLE_ORreinterpret_cast<char const *>("STR_TABLE_OR" "\004" u8"OR" )) ) | ||||
3279 | { | ||||
3280 | rEntry.eConnect = SC_OR; | ||||
3281 | bValid = true; | ||||
3282 | } | ||||
3283 | } | ||||
3284 | // Second column field name | ||||
3285 | if ((nIndex < 1) || bValid) | ||||
3286 | { | ||||
3287 | bool bFound = false; | ||||
3288 | GetUpperCellString(nCol1 + 1, nRow, aCellStr); | ||||
3289 | for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++) | ||||
3290 | { | ||||
3291 | OUString aFieldStr; | ||||
3292 | if ( nTab == nDBTab ) | ||||
3293 | GetUpperCellString(i, nDBRow1, aFieldStr); | ||||
3294 | else | ||||
3295 | rDocument.GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr); | ||||
3296 | bFound = (aCellStr == aFieldStr); | ||||
3297 | if (bFound) | ||||
3298 | { | ||||
3299 | rEntry.nField = i; | ||||
3300 | bValid = true; | ||||
3301 | } | ||||
3302 | else | ||||
3303 | bValid = false; | ||||
3304 | } | ||||
3305 | } | ||||
3306 | // Third column operator =<>... | ||||
3307 | if (bValid) | ||||
3308 | { | ||||
3309 | GetUpperCellString(nCol1 + 2, nRow, aCellStr); | ||||
3310 | if (aCellStr.startsWith("<")) | ||||
3311 | { | ||||
3312 | if (aCellStr[1] == '>') | ||||
3313 | rEntry.eOp = SC_NOT_EQUAL; | ||||
3314 | else if (aCellStr[1] == '=') | ||||
3315 | rEntry.eOp = SC_LESS_EQUAL; | ||||
3316 | else | ||||
3317 | rEntry.eOp = SC_LESS; | ||||
3318 | } | ||||
3319 | else if (aCellStr.startsWith(">")) | ||||
3320 | { | ||||
3321 | if (aCellStr[1] == '=') | ||||
3322 | rEntry.eOp = SC_GREATER_EQUAL; | ||||
3323 | else | ||||
3324 | rEntry.eOp = SC_GREATER; | ||||
3325 | } | ||||
3326 | else if (aCellStr.startsWith("=")) | ||||
3327 | rEntry.eOp = SC_EQUAL; | ||||
3328 | |||||
3329 | } | ||||
3330 | // Fourth column values | ||||
3331 | if (bValid) | ||||
3332 | { | ||||
3333 | OUString aStr; | ||||
3334 | GetString(nCol1 + 3, nRow, aStr); | ||||
3335 | rEntry.GetQueryItem().maString = rPool.intern(aStr); | ||||
3336 | rEntry.bDoQuery = true; | ||||
3337 | } | ||||
3338 | nIndex++; | ||||
3339 | nRow++; | ||||
3340 | } | ||||
3341 | while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ ); | ||||
3342 | return bValid; | ||||
3343 | } | ||||
3344 | |||||
3345 | bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) | ||||
3346 | { | ||||
3347 | SCSIZE i, nCount; | ||||
3348 | PutInOrder(nCol1, nCol2); | ||||
3349 | PutInOrder(nRow1, nRow2); | ||||
3350 | |||||
3351 | nCount = rQueryParam.GetEntryCount(); | ||||
3352 | for (i=0; i < nCount; i++) | ||||
3353 | rQueryParam.GetEntry(i).Clear(); | ||||
3354 | |||||
3355 | // Standard query table | ||||
3356 | bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam); | ||||
3357 | // Excel Query table | ||||
3358 | if (!bValid) | ||||
3359 | bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam); | ||||
3360 | |||||
3361 | SvNumberFormatter* pFormatter = rDocument.GetFormatTable(); | ||||
3362 | nCount = rQueryParam.GetEntryCount(); | ||||
3363 | |||||
3364 | if (bValid) | ||||
3365 | { | ||||
3366 | // bQueryByString must be set | ||||
3367 | for (i=0; i < nCount; i++) | ||||
3368 | { | ||||
3369 | ScQueryEntry::Item& rItem = rQueryParam.GetEntry(i).GetQueryItem(); | ||||
3370 | |||||
3371 | sal_uInt32 nIndex = 0; | ||||
3372 | bool bNumber = pFormatter->IsNumberFormat( | ||||
3373 | rItem.maString.getString(), nIndex, rItem.mfVal); | ||||
3374 | |||||
3375 | rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString; | ||||
3376 | } | ||||
3377 | } | ||||
3378 | else | ||||
3379 | { | ||||
3380 | for (i=0; i < nCount; i++) | ||||
3381 | rQueryParam.GetEntry(i).Clear(); | ||||
3382 | } | ||||
3383 | return bValid; | ||||
3384 | } | ||||
3385 | |||||
3386 | bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const | ||||
3387 | { | ||||
3388 | if (nStartRow == nEndRow) | ||||
3389 | // Assume only data. | ||||
3390 | /* XXX NOTE: previous behavior still checked this one row and could | ||||
3391 | * evaluate it has header row, but that doesn't make much sense. */ | ||||
3392 | return false; | ||||
3393 | |||||
3394 | if (nStartCol == nEndCol) | ||||
3395 | { | ||||
3396 | CellType eFirstCellType = GetCellType(nStartCol, nStartRow); | ||||
3397 | CellType eSecondCellType = GetCellType(nStartCol, nStartRow+1); | ||||
3398 | return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) && | ||||
3399 | (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT)); | ||||
3400 | } | ||||
3401 | |||||
3402 | for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) | ||||
3403 | { | ||||
3404 | CellType eType = GetCellType( nCol, nStartRow ); | ||||
3405 | // Any non-text cell in first row => not headers. | ||||
3406 | if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) | ||||
3407 | return false; | ||||
3408 | } | ||||
3409 | |||||
3410 | // First row all text cells, any non-text cell in second row => headers. | ||||
3411 | SCROW nTestRow = nStartRow + 1; | ||||
3412 | for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) | ||||
3413 | { | ||||
3414 | CellType eType = GetCellType( nCol, nTestRow ); | ||||
3415 | if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) | ||||
3416 | return true; | ||||
3417 | } | ||||
3418 | |||||
3419 | // Also second row all text cells => first row not headers. | ||||
3420 | return false; | ||||
3421 | } | ||||
3422 | |||||
3423 | bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const | ||||
3424 | { | ||||
3425 | if (nStartCol == nEndCol) | ||||
3426 | // Assume only data. | ||||
3427 | /* XXX NOTE: previous behavior still checked this one column and could | ||||
3428 | * evaluate it has header column, but that doesn't make much sense. */ | ||||
3429 | return false; | ||||
3430 | |||||
3431 | if (nStartRow == nEndRow) | ||||
3432 | { | ||||
3433 | CellType eFirstCellType = GetCellType(nStartCol, nStartRow); | ||||
3434 | CellType eSecondCellType = GetCellType(nStartCol+1, nStartRow); | ||||
3435 | return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) && | ||||
3436 | (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT)); | ||||
3437 | } | ||||
3438 | |||||
3439 | for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++) | ||||
3440 | { | ||||
3441 | CellType eType = GetCellType( nStartCol, nRow ); | ||||
3442 | // Any non-text cell in first column => not headers. | ||||
3443 | if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) | ||||
3444 | return false; | ||||
3445 | } | ||||
3446 | |||||
3447 | // First column all text cells, any non-text cell in second column => headers. | ||||
3448 | SCCOL nTestCol = nStartCol + 1; | ||||
3449 | for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++) | ||||
3450 | { | ||||
3451 | CellType eType = GetCellType( nRow, nTestCol ); | ||||
3452 | if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) | ||||
3453 | return true; | ||||
3454 | } | ||||
3455 | |||||
3456 | // Also second column all text cells => first column not headers. | ||||
3457 | return false; | ||||
3458 | } | ||||
3459 | |||||
3460 | void ScTable::GetFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEntries& rFilterEntries ) | ||||
3461 | { | ||||
3462 | sc::ColumnBlockConstPosition aBlockPos; | ||||
3463 | aCol[nCol].InitBlockPosition(aBlockPos); | ||||
3464 | aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries); | ||||
3465 | } | ||||
3466 | |||||
3467 | void ScTable::GetFilteredFilterEntries( | ||||
3468 | SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, ScFilterEntries& rFilterEntries ) | ||||
3469 | { | ||||
3470 | sc::ColumnBlockConstPosition aBlockPos; | ||||
3471 | aCol[nCol].InitBlockPosition(aBlockPos); | ||||
3472 | |||||
3473 | // remove the entry for this column from the query parameter | ||||
3474 | ScQueryParam aParam( rParam ); | ||||
3475 | aParam.RemoveEntryByField(nCol); | ||||
3476 | |||||
3477 | lcl_PrepareQuery(&rDocument, this, aParam); | ||||
3478 | for ( SCROW j = nRow1; j <= nRow2; ++j ) | ||||
| |||||
3479 | { | ||||
3480 | if (ValidQuery(j, aParam)) | ||||
3481 | { | ||||
3482 | aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries); | ||||
3483 | } | ||||
3484 | } | ||||
3485 | } | ||||
3486 | |||||
3487 | bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings, bool bLimit) | ||||
3488 | { | ||||
3489 | return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit ); | ||||
3490 | } | ||||
3491 | |||||
3492 | sal_uLong ScTable::GetCellCount() const | ||||
3493 | { | ||||
3494 | sal_uLong nCellCount = 0; | ||||
3495 | |||||
3496 | for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ ) | ||||
3497 | nCellCount += aCol[nCol].GetCellCount(); | ||||
3498 | |||||
3499 | return nCellCount; | ||||
3500 | } | ||||
3501 | |||||
3502 | sal_uLong ScTable::GetWeightedCount() const | ||||
3503 | { | ||||
3504 | sal_uLong nCellCount = 0; | ||||
3505 | |||||
3506 | for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ ) | ||||
3507 | nCellCount += aCol[nCol].GetWeightedCount(); | ||||
3508 | |||||
3509 | return nCellCount; | ||||
3510 | } | ||||
3511 | |||||
3512 | sal_uLong ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const | ||||
3513 | { | ||||
3514 | sal_uLong nCellCount = 0; | ||||
3515 | |||||
3516 | for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ ) | ||||
3517 | nCellCount += aCol[nCol].GetWeightedCount(nStartRow, nEndRow); | ||||
3518 | |||||
3519 | return nCellCount; | ||||
3520 | } | ||||
3521 | |||||
3522 | sal_uLong ScTable::GetCodeCount() const | ||||
3523 | { | ||||
3524 | sal_uLong nCodeCount = 0; | ||||
3525 | |||||
3526 | for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ ) | ||||
3527 | if ( aCol[nCol].GetCellCount() ) | ||||
3528 | nCodeCount += aCol[nCol].GetCodeCount(); | ||||
3529 | |||||
3530 | return nCodeCount; | ||||
3531 | } | ||||
3532 | |||||
3533 | sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart, | ||||
3534 | SCROW nRowEnd, rtl_TextEncoding eCharSet ) const | ||||
3535 | { | ||||
3536 | if ( IsColValid( nCol ) ) | ||||
3537 | return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet ); | ||||
3538 | else | ||||
3539 | return 0; | ||||
3540 | } | ||||
3541 | |||||
3542 | sal_Int32 ScTable::GetMaxNumberStringLen( | ||||
3543 | sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const | ||||
3544 | { | ||||
3545 | if ( IsColValid( nCol ) ) | ||||
3546 | return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd ); | ||||
3547 | else | ||||
3548 | return 0; | ||||
3549 | } | ||||
3550 | |||||
3551 | void ScTable::UpdateSelectionFunction( ScFunctionData& rData, const ScMarkData& rMark ) | ||||
3552 | { | ||||
3553 | ScRangeList aRanges = rMark.GetMarkedRangesForTab( nTab ); | ||||
3554 | ScRange aMarkArea( ScAddress::UNINITIALIZED ); | ||||
3555 | if (rMark.IsMultiMarked()) | ||||
3556 | rMark.GetMultiMarkArea( aMarkArea ); | ||||
3557 | else if (rMark.IsMarked()) | ||||
3558 | rMark.GetMarkArea( aMarkArea ); | ||||
3559 | else | ||||
3560 | { | ||||
3561 | assert(!"ScTable::UpdateSelectionFunction - called without anything marked")(static_cast <bool> (!"ScTable::UpdateSelectionFunction - called without anything marked" ) ? void (0) : __assert_fail ("!\"ScTable::UpdateSelectionFunction - called without anything marked\"" , "/home/maarten/src/libreoffice/core/sc/source/core/data/table3.cxx" , 3561, __extension__ __PRETTY_FUNCTION__)); | ||||
3562 | aMarkArea.aStart.SetCol(0); | ||||
3563 | aMarkArea.aEnd.SetCol(rDocument.MaxCol()); | ||||
3564 | } | ||||
3565 | const SCCOL nStartCol = aMarkArea.aStart.Col(); | ||||
3566 | const SCCOL nEndCol = ClampToAllocatedColumns(aMarkArea.aEnd.Col()); | ||||
3567 | for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol) | ||||
3568 | { | ||||
3569 | if (mpColFlags && ColHidden(nCol)) | ||||
3570 | continue; | ||||
3571 | |||||
3572 | aCol[nCol].UpdateSelectionFunction(aRanges, rData, *mpHiddenRows); | ||||
3573 | } | ||||
3574 | } | ||||
3575 | |||||
3576 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | // Iterators -*- C++ -*- |
2 | |
3 | // Copyright (C) 2001-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 | /* |
26 | * |
27 | * Copyright (c) 1994 |
28 | * Hewlett-Packard Company |
29 | * |
30 | * Permission to use, copy, modify, distribute and sell this software |
31 | * and its documentation for any purpose is hereby granted without fee, |
32 | * provided that the above copyright notice appear in all copies and |
33 | * that both that copyright notice and this permission notice appear |
34 | * in supporting documentation. Hewlett-Packard Company makes no |
35 | * representations about the suitability of this software for any |
36 | * purpose. It is provided "as is" without express or implied warranty. |
37 | * |
38 | * |
39 | * Copyright (c) 1996-1998 |
40 | * Silicon Graphics Computer Systems, Inc. |
41 | * |
42 | * Permission to use, copy, modify, distribute and sell this software |
43 | * and its documentation for any purpose is hereby granted without fee, |
44 | * provided that the above copyright notice appear in all copies and |
45 | * that both that copyright notice and this permission notice appear |
46 | * in supporting documentation. Silicon Graphics makes no |
47 | * representations about the suitability of this software for any |
48 | * purpose. It is provided "as is" without express or implied warranty. |
49 | */ |
50 | |
51 | /** @file bits/stl_iterator.h |
52 | * This is an internal header file, included by other library headers. |
53 | * Do not attempt to use it directly. @headername{iterator} |
54 | * |
55 | * This file implements reverse_iterator, back_insert_iterator, |
56 | * front_insert_iterator, insert_iterator, __normal_iterator, and their |
57 | * supporting functions and overloaded operators. |
58 | */ |
59 | |
60 | #ifndef _STL_ITERATOR_H1 |
61 | #define _STL_ITERATOR_H1 1 |
62 | |
63 | #include <bits/cpp_type_traits.h> |
64 | #include <ext/type_traits.h> |
65 | #include <bits/move.h> |
66 | #include <bits/ptr_traits.h> |
67 | |
68 | #if __cplusplus201703L >= 201103L |
69 | # include <type_traits> |
70 | #endif |
71 | |
72 | #if __cplusplus201703L > 201703L |
73 | # define __cpp_lib_array_constexpr201803L 201811L |
74 | # define __cpp_lib_constexpr_iterator 201811L |
75 | #elif __cplusplus201703L == 201703L |
76 | # define __cpp_lib_array_constexpr201803L 201803L |
77 | #endif |
78 | |
79 | #if __cplusplus201703L > 201703L |
80 | # include <compare> |
81 | # include <new> |
82 | # include <bits/iterator_concepts.h> |
83 | #endif |
84 | |
85 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
86 | { |
87 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
88 | |
89 | /** |
90 | * @addtogroup iterators |
91 | * @{ |
92 | */ |
93 | |
94 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
95 | namespace __detail |
96 | { |
97 | // Weaken iterator_category _Cat to _Limit if it is derived from that, |
98 | // otherwise use _Otherwise. |
99 | template<typename _Cat, typename _Limit, typename _Otherwise = _Cat> |
100 | using __clamp_iter_cat |
101 | = conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>; |
102 | } |
103 | #endif |
104 | |
105 | // 24.4.1 Reverse iterators |
106 | /** |
107 | * Bidirectional and random access iterators have corresponding reverse |
108 | * %iterator adaptors that iterate through the data structure in the |
109 | * opposite direction. They have the same signatures as the corresponding |
110 | * iterators. The fundamental relation between a reverse %iterator and its |
111 | * corresponding %iterator @c i is established by the identity: |
112 | * @code |
113 | * &*(reverse_iterator(i)) == &*(i - 1) |
114 | * @endcode |
115 | * |
116 | * <em>This mapping is dictated by the fact that while there is always a |
117 | * pointer past the end of an array, there might not be a valid pointer |
118 | * before the beginning of an array.</em> [24.4.1]/1,2 |
119 | * |
120 | * Reverse iterators can be tricky and surprising at first. Their |
121 | * semantics make sense, however, and the trickiness is a side effect of |
122 | * the requirement that the iterators must be safe. |
123 | */ |
124 | template<typename _Iterator> |
125 | class reverse_iterator |
126 | : public iterator<typename iterator_traits<_Iterator>::iterator_category, |
127 | typename iterator_traits<_Iterator>::value_type, |
128 | typename iterator_traits<_Iterator>::difference_type, |
129 | typename iterator_traits<_Iterator>::pointer, |
130 | typename iterator_traits<_Iterator>::reference> |
131 | { |
132 | protected: |
133 | _Iterator current; |
134 | |
135 | typedef iterator_traits<_Iterator> __traits_type; |
136 | |
137 | public: |
138 | typedef _Iterator iterator_type; |
139 | typedef typename __traits_type::difference_type difference_type; |
140 | typedef typename __traits_type::pointer pointer; |
141 | typedef typename __traits_type::reference reference; |
142 | |
143 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
144 | using iterator_concept |
145 | = conditional_t<random_access_iterator<_Iterator>, |
146 | random_access_iterator_tag, |
147 | bidirectional_iterator_tag>; |
148 | using iterator_category |
149 | = __detail::__clamp_iter_cat<typename __traits_type::iterator_category, |
150 | random_access_iterator_tag>; |
151 | #endif |
152 | |
153 | /** |
154 | * The default constructor value-initializes member @p current. |
155 | * If it is a pointer, that means it is zero-initialized. |
156 | */ |
157 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
158 | // 235 No specification of default ctor for reverse_iterator |
159 | // 1012. reverse_iterator default ctor should value initialize |
160 | _GLIBCXX17_CONSTEXPRconstexpr |
161 | reverse_iterator() : current() { } |
162 | |
163 | /** |
164 | * This %iterator will move in the opposite direction that @p x does. |
165 | */ |
166 | explicit _GLIBCXX17_CONSTEXPRconstexpr |
167 | reverse_iterator(iterator_type __x) : current(__x) { } |
168 | |
169 | /** |
170 | * The copy constructor is normal. |
171 | */ |
172 | _GLIBCXX17_CONSTEXPRconstexpr |
173 | reverse_iterator(const reverse_iterator& __x) |
174 | : current(__x.current) { } |
175 | |
176 | #if __cplusplus201703L >= 201103L |
177 | reverse_iterator& operator=(const reverse_iterator&) = default; |
178 | #endif |
179 | |
180 | /** |
181 | * A %reverse_iterator across other types can be copied if the |
182 | * underlying %iterator can be converted to the type of @c current. |
183 | */ |
184 | template<typename _Iter> |
185 | _GLIBCXX17_CONSTEXPRconstexpr |
186 | reverse_iterator(const reverse_iterator<_Iter>& __x) |
187 | : current(__x.base()) { } |
188 | |
189 | /** |
190 | * @return @c current, the %iterator used for underlying work. |
191 | */ |
192 | _GLIBCXX17_CONSTEXPRconstexpr iterator_type |
193 | base() const |
194 | { return current; } |
195 | |
196 | /** |
197 | * @return A reference to the value at @c --current |
198 | * |
199 | * This requires that @c --current is dereferenceable. |
200 | * |
201 | * @warning This implementation requires that for an iterator of the |
202 | * underlying iterator type, @c x, a reference obtained by |
203 | * @c *x remains valid after @c x has been modified or |
204 | * destroyed. This is a bug: http://gcc.gnu.org/PR51823 |
205 | */ |
206 | _GLIBCXX17_CONSTEXPRconstexpr reference |
207 | operator*() const |
208 | { |
209 | _Iterator __tmp = current; |
210 | return *--__tmp; |
211 | } |
212 | |
213 | /** |
214 | * @return A pointer to the value at @c --current |
215 | * |
216 | * This requires that @c --current is dereferenceable. |
217 | */ |
218 | _GLIBCXX17_CONSTEXPRconstexpr pointer |
219 | operator->() const |
220 | #if __cplusplus201703L > 201703L && __cpp_concepts >= 201907L |
221 | requires is_pointer_v<_Iterator> |
222 | || requires(const _Iterator __i) { __i.operator->(); } |
223 | #endif |
224 | { |
225 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
226 | // 1052. operator-> should also support smart pointers |
227 | _Iterator __tmp = current; |
228 | --__tmp; |
229 | return _S_to_pointer(__tmp); |
230 | } |
231 | |
232 | /** |
233 | * @return @c *this |
234 | * |
235 | * Decrements the underlying iterator. |
236 | */ |
237 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
238 | operator++() |
239 | { |
240 | --current; |
241 | return *this; |
242 | } |
243 | |
244 | /** |
245 | * @return The original value of @c *this |
246 | * |
247 | * Decrements the underlying iterator. |
248 | */ |
249 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
250 | operator++(int) |
251 | { |
252 | reverse_iterator __tmp = *this; |
253 | --current; |
254 | return __tmp; |
255 | } |
256 | |
257 | /** |
258 | * @return @c *this |
259 | * |
260 | * Increments the underlying iterator. |
261 | */ |
262 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
263 | operator--() |
264 | { |
265 | ++current; |
266 | return *this; |
267 | } |
268 | |
269 | /** |
270 | * @return A reverse_iterator with the previous value of @c *this |
271 | * |
272 | * Increments the underlying iterator. |
273 | */ |
274 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
275 | operator--(int) |
276 | { |
277 | reverse_iterator __tmp = *this; |
278 | ++current; |
279 | return __tmp; |
280 | } |
281 | |
282 | /** |
283 | * @return A reverse_iterator that refers to @c current - @a __n |
284 | * |
285 | * The underlying iterator must be a Random Access Iterator. |
286 | */ |
287 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
288 | operator+(difference_type __n) const |
289 | { return reverse_iterator(current - __n); } |
290 | |
291 | /** |
292 | * @return *this |
293 | * |
294 | * Moves the underlying iterator backwards @a __n steps. |
295 | * The underlying iterator must be a Random Access Iterator. |
296 | */ |
297 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
298 | operator+=(difference_type __n) |
299 | { |
300 | current -= __n; |
301 | return *this; |
302 | } |
303 | |
304 | /** |
305 | * @return A reverse_iterator that refers to @c current - @a __n |
306 | * |
307 | * The underlying iterator must be a Random Access Iterator. |
308 | */ |
309 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
310 | operator-(difference_type __n) const |
311 | { return reverse_iterator(current + __n); } |
312 | |
313 | /** |
314 | * @return *this |
315 | * |
316 | * Moves the underlying iterator forwards @a __n steps. |
317 | * The underlying iterator must be a Random Access Iterator. |
318 | */ |
319 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
320 | operator-=(difference_type __n) |
321 | { |
322 | current += __n; |
323 | return *this; |
324 | } |
325 | |
326 | /** |
327 | * @return The value at @c current - @a __n - 1 |
328 | * |
329 | * The underlying iterator must be a Random Access Iterator. |
330 | */ |
331 | _GLIBCXX17_CONSTEXPRconstexpr reference |
332 | operator[](difference_type __n) const |
333 | { return *(*this + __n); } |
334 | |
335 | private: |
336 | template<typename _Tp> |
337 | static _GLIBCXX17_CONSTEXPRconstexpr _Tp* |
338 | _S_to_pointer(_Tp* __p) |
339 | { return __p; } |
340 | |
341 | template<typename _Tp> |
342 | static _GLIBCXX17_CONSTEXPRconstexpr pointer |
343 | _S_to_pointer(_Tp __t) |
344 | { return __t.operator->(); } |
345 | }; |
346 | |
347 | //@{ |
348 | /** |
349 | * @param __x A %reverse_iterator. |
350 | * @param __y A %reverse_iterator. |
351 | * @return A simple bool. |
352 | * |
353 | * Reverse iterators forward comparisons to their underlying base() |
354 | * iterators. |
355 | * |
356 | */ |
357 | #if __cplusplus201703L <= 201703L || ! defined __cpp_lib_concepts |
358 | template<typename _Iterator> |
359 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
360 | operator==(const reverse_iterator<_Iterator>& __x, |
361 | const reverse_iterator<_Iterator>& __y) |
362 | { return __x.base() == __y.base(); } |
363 | |
364 | template<typename _Iterator> |
365 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
366 | operator<(const reverse_iterator<_Iterator>& __x, |
367 | const reverse_iterator<_Iterator>& __y) |
368 | { return __y.base() < __x.base(); } |
369 | |
370 | template<typename _Iterator> |
371 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
372 | operator!=(const reverse_iterator<_Iterator>& __x, |
373 | const reverse_iterator<_Iterator>& __y) |
374 | { return !(__x == __y); } |
375 | |
376 | template<typename _Iterator> |
377 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
378 | operator>(const reverse_iterator<_Iterator>& __x, |
379 | const reverse_iterator<_Iterator>& __y) |
380 | { return __y < __x; } |
381 | |
382 | template<typename _Iterator> |
383 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
384 | operator<=(const reverse_iterator<_Iterator>& __x, |
385 | const reverse_iterator<_Iterator>& __y) |
386 | { return !(__y < __x); } |
387 | |
388 | template<typename _Iterator> |
389 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
390 | operator>=(const reverse_iterator<_Iterator>& __x, |
391 | const reverse_iterator<_Iterator>& __y) |
392 | { return !(__x < __y); } |
393 | |
394 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
395 | // DR 280. Comparison of reverse_iterator to const reverse_iterator. |
396 | template<typename _IteratorL, typename _IteratorR> |
397 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
398 | operator==(const reverse_iterator<_IteratorL>& __x, |
399 | const reverse_iterator<_IteratorR>& __y) |
400 | { return __x.base() == __y.base(); } |
401 | |
402 | template<typename _IteratorL, typename _IteratorR> |
403 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
404 | operator<(const reverse_iterator<_IteratorL>& __x, |
405 | const reverse_iterator<_IteratorR>& __y) |
406 | { return __y.base() < __x.base(); } |
407 | |
408 | template<typename _IteratorL, typename _IteratorR> |
409 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
410 | operator!=(const reverse_iterator<_IteratorL>& __x, |
411 | const reverse_iterator<_IteratorR>& __y) |
412 | { return !(__x == __y); } |
413 | |
414 | template<typename _IteratorL, typename _IteratorR> |
415 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
416 | operator>(const reverse_iterator<_IteratorL>& __x, |
417 | const reverse_iterator<_IteratorR>& __y) |
418 | { return __y < __x; } |
419 | |
420 | template<typename _IteratorL, typename _IteratorR> |
421 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
422 | operator<=(const reverse_iterator<_IteratorL>& __x, |
423 | const reverse_iterator<_IteratorR>& __y) |
424 | { return !(__y < __x); } |
425 | |
426 | template<typename _IteratorL, typename _IteratorR> |
427 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
428 | operator>=(const reverse_iterator<_IteratorL>& __x, |
429 | const reverse_iterator<_IteratorR>& __y) |
430 | { return !(__x < __y); } |
431 | #else // C++20 |
432 | template<typename _IteratorL, typename _IteratorR> |
433 | constexpr bool |
434 | operator==(const reverse_iterator<_IteratorL>& __x, |
435 | const reverse_iterator<_IteratorR>& __y) |
436 | requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; } |
437 | { return __x.base() == __y.base(); } |
438 | |
439 | template<typename _IteratorL, typename _IteratorR> |
440 | constexpr bool |
441 | operator!=(const reverse_iterator<_IteratorL>& __x, |
442 | const reverse_iterator<_IteratorR>& __y) |
443 | requires requires { { __x.base() != __y.base() } -> convertible_to<bool>; } |
444 | { return __x.base() != __y.base(); } |
445 | |
446 | template<typename _IteratorL, typename _IteratorR> |
447 | constexpr bool |
448 | operator<(const reverse_iterator<_IteratorL>& __x, |
449 | const reverse_iterator<_IteratorR>& __y) |
450 | requires requires { { __x.base() > __y.base() } -> convertible_to<bool>; } |
451 | { return __x.base() > __y.base(); } |
452 | |
453 | template<typename _IteratorL, typename _IteratorR> |
454 | constexpr bool |
455 | operator>(const reverse_iterator<_IteratorL>& __x, |
456 | const reverse_iterator<_IteratorR>& __y) |
457 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
458 | { return __x.base() < __y.base(); } |
459 | |
460 | template<typename _IteratorL, typename _IteratorR> |
461 | constexpr bool |
462 | operator<=(const reverse_iterator<_IteratorL>& __x, |
463 | const reverse_iterator<_IteratorR>& __y) |
464 | requires requires { { __x.base() >= __y.base() } -> convertible_to<bool>; } |
465 | { return __x.base() >= __y.base(); } |
466 | |
467 | template<typename _IteratorL, typename _IteratorR> |
468 | constexpr bool |
469 | operator>=(const reverse_iterator<_IteratorL>& __x, |
470 | const reverse_iterator<_IteratorR>& __y) |
471 | requires requires { { __x.base() <= __y.base() } -> convertible_to<bool>; } |
472 | { return __x.base() <= __y.base(); } |
473 | |
474 | template<typename _IteratorL, |
475 | three_way_comparable_with<_IteratorL> _IteratorR> |
476 | constexpr compare_three_way_result_t<_IteratorL, _IteratorR> |
477 | operator<=>(const reverse_iterator<_IteratorL>& __x, |
478 | const reverse_iterator<_IteratorR>& __y) |
479 | { return __y.base() <=> __x.base(); } |
480 | #endif // C++20 |
481 | //@} |
482 | |
483 | #if __cplusplus201703L < 201103L |
484 | template<typename _Iterator> |
485 | inline typename reverse_iterator<_Iterator>::difference_type |
486 | operator-(const reverse_iterator<_Iterator>& __x, |
487 | const reverse_iterator<_Iterator>& __y) |
488 | { return __y.base() - __x.base(); } |
489 | |
490 | template<typename _IteratorL, typename _IteratorR> |
491 | inline typename reverse_iterator<_IteratorL>::difference_type |
492 | operator-(const reverse_iterator<_IteratorL>& __x, |
493 | const reverse_iterator<_IteratorR>& __y) |
494 | { return __y.base() - __x.base(); } |
495 | #else |
496 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
497 | // DR 685. reverse_iterator/move_iterator difference has invalid signatures |
498 | template<typename _IteratorL, typename _IteratorR> |
499 | inline _GLIBCXX17_CONSTEXPRconstexpr auto |
500 | operator-(const reverse_iterator<_IteratorL>& __x, |
501 | const reverse_iterator<_IteratorR>& __y) |
502 | -> decltype(__y.base() - __x.base()) |
503 | { return __y.base() - __x.base(); } |
504 | #endif |
505 | |
506 | template<typename _Iterator> |
507 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
508 | operator+(typename reverse_iterator<_Iterator>::difference_type __n, |
509 | const reverse_iterator<_Iterator>& __x) |
510 | { return reverse_iterator<_Iterator>(__x.base() - __n); } |
511 | |
512 | #if __cplusplus201703L >= 201103L |
513 | // Same as C++14 make_reverse_iterator but used in C++11 mode too. |
514 | template<typename _Iterator> |
515 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
516 | __make_reverse_iterator(_Iterator __i) |
517 | { return reverse_iterator<_Iterator>(__i); } |
518 | |
519 | # if __cplusplus201703L >= 201402L |
520 | # define __cpp_lib_make_reverse_iterator201402 201402 |
521 | |
522 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
523 | // DR 2285. make_reverse_iterator |
524 | /// Generator function for reverse_iterator. |
525 | template<typename _Iterator> |
526 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
527 | make_reverse_iterator(_Iterator __i) |
528 | { return reverse_iterator<_Iterator>(__i); } |
529 | |
530 | # if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
531 | template<typename _Iterator1, typename _Iterator2> |
532 | requires (!sized_sentinel_for<_Iterator1, _Iterator2>) |
533 | inline constexpr bool |
534 | disable_sized_sentinel_for<reverse_iterator<_Iterator1>, |
535 | reverse_iterator<_Iterator2>> = true; |
536 | # endif // C++20 |
537 | # endif // C++14 |
538 | |
539 | template<typename _Iterator> |
540 | _GLIBCXX20_CONSTEXPR |
541 | auto |
542 | __niter_base(reverse_iterator<_Iterator> __it) |
543 | -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) |
544 | { return __make_reverse_iterator(__niter_base(__it.base())); } |
545 | |
546 | template<typename _Iterator> |
547 | struct __is_move_iterator<reverse_iterator<_Iterator> > |
548 | : __is_move_iterator<_Iterator> |
549 | { }; |
550 | |
551 | template<typename _Iterator> |
552 | _GLIBCXX20_CONSTEXPR |
553 | auto |
554 | __miter_base(reverse_iterator<_Iterator> __it) |
555 | -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) |
556 | { return __make_reverse_iterator(__miter_base(__it.base())); } |
557 | #endif // C++11 |
558 | |
559 | // 24.4.2.2.1 back_insert_iterator |
560 | /** |
561 | * @brief Turns assignment into insertion. |
562 | * |
563 | * These are output iterators, constructed from a container-of-T. |
564 | * Assigning a T to the iterator appends it to the container using |
565 | * push_back. |
566 | * |
567 | * Tip: Using the back_inserter function to create these iterators can |
568 | * save typing. |
569 | */ |
570 | template<typename _Container> |
571 | class back_insert_iterator |
572 | : public iterator<output_iterator_tag, void, void, void, void> |
573 | { |
574 | protected: |
575 | _Container* container; |
576 | |
577 | public: |
578 | /// A nested typedef for the type of whatever container you used. |
579 | typedef _Container container_type; |
580 | #if __cplusplus201703L > 201703L |
581 | using difference_type = ptrdiff_t; |
582 | |
583 | constexpr back_insert_iterator() noexcept : container(nullptr) { } |
584 | #endif |
585 | |
586 | /// The only way to create this %iterator is with a container. |
587 | explicit _GLIBCXX20_CONSTEXPR |
588 | back_insert_iterator(_Container& __x) |
589 | : container(std::__addressof(__x)) { } |
590 | |
591 | /** |
592 | * @param __value An instance of whatever type |
593 | * container_type::const_reference is; presumably a |
594 | * reference-to-const T for container<T>. |
595 | * @return This %iterator, for chained operations. |
596 | * |
597 | * This kind of %iterator doesn't really have a @a position in the |
598 | * container (you can think of the position as being permanently at |
599 | * the end, if you like). Assigning a value to the %iterator will |
600 | * always append the value to the end of the container. |
601 | */ |
602 | #if __cplusplus201703L < 201103L |
603 | back_insert_iterator& |
604 | operator=(typename _Container::const_reference __value) |
605 | { |
606 | container->push_back(__value); |
607 | return *this; |
608 | } |
609 | #else |
610 | _GLIBCXX20_CONSTEXPR |
611 | back_insert_iterator& |
612 | operator=(const typename _Container::value_type& __value) |
613 | { |
614 | container->push_back(__value); |
615 | return *this; |
616 | } |
617 | |
618 | _GLIBCXX20_CONSTEXPR |
619 | back_insert_iterator& |
620 | operator=(typename _Container::value_type&& __value) |
621 | { |
622 | container->push_back(std::move(__value)); |
623 | return *this; |
624 | } |
625 | #endif |
626 | |
627 | /// Simply returns *this. |
628 | _GLIBCXX20_CONSTEXPR |
629 | back_insert_iterator& |
630 | operator*() |
631 | { return *this; } |
632 | |
633 | /// Simply returns *this. (This %iterator does not @a move.) |
634 | _GLIBCXX20_CONSTEXPR |
635 | back_insert_iterator& |
636 | operator++() |
637 | { return *this; } |
638 | |
639 | /// Simply returns *this. (This %iterator does not @a move.) |
640 | _GLIBCXX20_CONSTEXPR |
641 | back_insert_iterator |
642 | operator++(int) |
643 | { return *this; } |
644 | }; |
645 | |
646 | /** |
647 | * @param __x A container of arbitrary type. |
648 | * @return An instance of back_insert_iterator working on @p __x. |
649 | * |
650 | * This wrapper function helps in creating back_insert_iterator instances. |
651 | * Typing the name of the %iterator requires knowing the precise full |
652 | * type of the container, which can be tedious and impedes generic |
653 | * programming. Using this function lets you take advantage of automatic |
654 | * template parameter deduction, making the compiler match the correct |
655 | * types for you. |
656 | */ |
657 | template<typename _Container> |
658 | _GLIBCXX20_CONSTEXPR |
659 | inline back_insert_iterator<_Container> |
660 | back_inserter(_Container& __x) |
661 | { return back_insert_iterator<_Container>(__x); } |
662 | |
663 | /** |
664 | * @brief Turns assignment into insertion. |
665 | * |
666 | * These are output iterators, constructed from a container-of-T. |
667 | * Assigning a T to the iterator prepends it to the container using |
668 | * push_front. |
669 | * |
670 | * Tip: Using the front_inserter function to create these iterators can |
671 | * save typing. |
672 | */ |
673 | template<typename _Container> |
674 | class front_insert_iterator |
675 | : public iterator<output_iterator_tag, void, void, void, void> |
676 | { |
677 | protected: |
678 | _Container* container; |
679 | |
680 | public: |
681 | /// A nested typedef for the type of whatever container you used. |
682 | typedef _Container container_type; |
683 | #if __cplusplus201703L > 201703L |
684 | using difference_type = ptrdiff_t; |
685 | |
686 | constexpr front_insert_iterator() noexcept : container(nullptr) { } |
687 | #endif |
688 | |
689 | /// The only way to create this %iterator is with a container. |
690 | explicit _GLIBCXX20_CONSTEXPR |
691 | front_insert_iterator(_Container& __x) |
692 | : container(std::__addressof(__x)) { } |
693 | |
694 | /** |
695 | * @param __value An instance of whatever type |
696 | * container_type::const_reference is; presumably a |
697 | * reference-to-const T for container<T>. |
698 | * @return This %iterator, for chained operations. |
699 | * |
700 | * This kind of %iterator doesn't really have a @a position in the |
701 | * container (you can think of the position as being permanently at |
702 | * the front, if you like). Assigning a value to the %iterator will |
703 | * always prepend the value to the front of the container. |
704 | */ |
705 | #if __cplusplus201703L < 201103L |
706 | front_insert_iterator& |
707 | operator=(typename _Container::const_reference __value) |
708 | { |
709 | container->push_front(__value); |
710 | return *this; |
711 | } |
712 | #else |
713 | _GLIBCXX20_CONSTEXPR |
714 | front_insert_iterator& |
715 | operator=(const typename _Container::value_type& __value) |
716 | { |
717 | container->push_front(__value); |
718 | return *this; |
719 | } |
720 | |
721 | _GLIBCXX20_CONSTEXPR |
722 | front_insert_iterator& |
723 | operator=(typename _Container::value_type&& __value) |
724 | { |
725 | container->push_front(std::move(__value)); |
726 | return *this; |
727 | } |
728 | #endif |
729 | |
730 | /// Simply returns *this. |
731 | _GLIBCXX20_CONSTEXPR |
732 | front_insert_iterator& |
733 | operator*() |
734 | { return *this; } |
735 | |
736 | /// Simply returns *this. (This %iterator does not @a move.) |
737 | _GLIBCXX20_CONSTEXPR |
738 | front_insert_iterator& |
739 | operator++() |
740 | { return *this; } |
741 | |
742 | /// Simply returns *this. (This %iterator does not @a move.) |
743 | _GLIBCXX20_CONSTEXPR |
744 | front_insert_iterator |
745 | operator++(int) |
746 | { return *this; } |
747 | }; |
748 | |
749 | /** |
750 | * @param __x A container of arbitrary type. |
751 | * @return An instance of front_insert_iterator working on @p x. |
752 | * |
753 | * This wrapper function helps in creating front_insert_iterator instances. |
754 | * Typing the name of the %iterator requires knowing the precise full |
755 | * type of the container, which can be tedious and impedes generic |
756 | * programming. Using this function lets you take advantage of automatic |
757 | * template parameter deduction, making the compiler match the correct |
758 | * types for you. |
759 | */ |
760 | template<typename _Container> |
761 | _GLIBCXX20_CONSTEXPR |
762 | inline front_insert_iterator<_Container> |
763 | front_inserter(_Container& __x) |
764 | { return front_insert_iterator<_Container>(__x); } |
765 | |
766 | /** |
767 | * @brief Turns assignment into insertion. |
768 | * |
769 | * These are output iterators, constructed from a container-of-T. |
770 | * Assigning a T to the iterator inserts it in the container at the |
771 | * %iterator's position, rather than overwriting the value at that |
772 | * position. |
773 | * |
774 | * (Sequences will actually insert a @e copy of the value before the |
775 | * %iterator's position.) |
776 | * |
777 | * Tip: Using the inserter function to create these iterators can |
778 | * save typing. |
779 | */ |
780 | template<typename _Container> |
781 | class insert_iterator |
782 | : public iterator<output_iterator_tag, void, void, void, void> |
783 | { |
784 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
785 | using _Iter = std::__detail::__range_iter_t<_Container>; |
786 | |
787 | protected: |
788 | _Container* container = nullptr; |
789 | _Iter iter = _Iter(); |
790 | #else |
791 | typedef typename _Container::iterator _Iter; |
792 | |
793 | protected: |
794 | _Container* container; |
795 | _Iter iter; |
796 | #endif |
797 | |
798 | public: |
799 | /// A nested typedef for the type of whatever container you used. |
800 | typedef _Container container_type; |
801 | |
802 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
803 | using difference_type = ptrdiff_t; |
804 | |
805 | insert_iterator() = default; |
806 | #endif |
807 | |
808 | /** |
809 | * The only way to create this %iterator is with a container and an |
810 | * initial position (a normal %iterator into the container). |
811 | */ |
812 | _GLIBCXX20_CONSTEXPR |
813 | insert_iterator(_Container& __x, _Iter __i) |
814 | : container(std::__addressof(__x)), iter(__i) {} |
815 | |
816 | /** |
817 | * @param __value An instance of whatever type |
818 | * container_type::const_reference is; presumably a |
819 | * reference-to-const T for container<T>. |
820 | * @return This %iterator, for chained operations. |
821 | * |
822 | * This kind of %iterator maintains its own position in the |
823 | * container. Assigning a value to the %iterator will insert the |
824 | * value into the container at the place before the %iterator. |
825 | * |
826 | * The position is maintained such that subsequent assignments will |
827 | * insert values immediately after one another. For example, |
828 | * @code |
829 | * // vector v contains A and Z |
830 | * |
831 | * insert_iterator i (v, ++v.begin()); |
832 | * i = 1; |
833 | * i = 2; |
834 | * i = 3; |
835 | * |
836 | * // vector v contains A, 1, 2, 3, and Z |
837 | * @endcode |
838 | */ |
839 | #if __cplusplus201703L < 201103L |
840 | insert_iterator& |
841 | operator=(typename _Container::const_reference __value) |
842 | { |
843 | iter = container->insert(iter, __value); |
844 | ++iter; |
845 | return *this; |
846 | } |
847 | #else |
848 | _GLIBCXX20_CONSTEXPR |
849 | insert_iterator& |
850 | operator=(const typename _Container::value_type& __value) |
851 | { |
852 | iter = container->insert(iter, __value); |
853 | ++iter; |
854 | return *this; |
855 | } |
856 | |
857 | _GLIBCXX20_CONSTEXPR |
858 | insert_iterator& |
859 | operator=(typename _Container::value_type&& __value) |
860 | { |
861 | iter = container->insert(iter, std::move(__value)); |
862 | ++iter; |
863 | return *this; |
864 | } |
865 | #endif |
866 | |
867 | /// Simply returns *this. |
868 | _GLIBCXX20_CONSTEXPR |
869 | insert_iterator& |
870 | operator*() |
871 | { return *this; } |
872 | |
873 | /// Simply returns *this. (This %iterator does not @a move.) |
874 | _GLIBCXX20_CONSTEXPR |
875 | insert_iterator& |
876 | operator++() |
877 | { return *this; } |
878 | |
879 | /// Simply returns *this. (This %iterator does not @a move.) |
880 | _GLIBCXX20_CONSTEXPR |
881 | insert_iterator& |
882 | operator++(int) |
883 | { return *this; } |
884 | }; |
885 | |
886 | /** |
887 | * @param __x A container of arbitrary type. |
888 | * @param __i An iterator into the container. |
889 | * @return An instance of insert_iterator working on @p __x. |
890 | * |
891 | * This wrapper function helps in creating insert_iterator instances. |
892 | * Typing the name of the %iterator requires knowing the precise full |
893 | * type of the container, which can be tedious and impedes generic |
894 | * programming. Using this function lets you take advantage of automatic |
895 | * template parameter deduction, making the compiler match the correct |
896 | * types for you. |
897 | */ |
898 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
899 | template<typename _Container> |
900 | constexpr insert_iterator<_Container> |
901 | inserter(_Container& __x, std::__detail::__range_iter_t<_Container> __i) |
902 | { return insert_iterator<_Container>(__x, __i); } |
903 | #else |
904 | template<typename _Container, typename _Iterator> |
905 | inline insert_iterator<_Container> |
906 | inserter(_Container& __x, _Iterator __i) |
907 | { |
908 | return insert_iterator<_Container>(__x, |
909 | typename _Container::iterator(__i)); |
910 | } |
911 | #endif |
912 | |
913 | // @} group iterators |
914 | |
915 | _GLIBCXX_END_NAMESPACE_VERSION |
916 | } // namespace |
917 | |
918 | namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
919 | { |
920 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
921 | |
922 | // This iterator adapter is @a normal in the sense that it does not |
923 | // change the semantics of any of the operators of its iterator |
924 | // parameter. Its primary purpose is to convert an iterator that is |
925 | // not a class, e.g. a pointer, into an iterator that is a class. |
926 | // The _Container parameter exists solely so that different containers |
927 | // using this template can instantiate different types, even if the |
928 | // _Iterator parameter is the same. |
929 | template<typename _Iterator, typename _Container> |
930 | class __normal_iterator |
931 | { |
932 | protected: |
933 | _Iterator _M_current; |
934 | |
935 | typedef std::iterator_traits<_Iterator> __traits_type; |
936 | |
937 | public: |
938 | typedef _Iterator iterator_type; |
939 | typedef typename __traits_type::iterator_category iterator_category; |
940 | typedef typename __traits_type::value_type value_type; |
941 | typedef typename __traits_type::difference_type difference_type; |
942 | typedef typename __traits_type::reference reference; |
943 | typedef typename __traits_type::pointer pointer; |
944 | |
945 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
946 | using iterator_concept = std::__detail::__iter_concept<_Iterator>; |
947 | #endif |
948 | |
949 | _GLIBCXX_CONSTEXPRconstexpr __normal_iterator() _GLIBCXX_NOEXCEPTnoexcept |
950 | : _M_current(_Iterator()) { } |
951 | |
952 | explicit _GLIBCXX20_CONSTEXPR |
953 | __normal_iterator(const _Iterator& __i) _GLIBCXX_NOEXCEPTnoexcept |
954 | : _M_current(__i) { } |
955 | |
956 | // Allow iterator to const_iterator conversion |
957 | template<typename _Iter> |
958 | _GLIBCXX20_CONSTEXPR |
959 | __normal_iterator(const __normal_iterator<_Iter, |
960 | typename __enable_if< |
961 | (std::__are_same<_Iter, typename _Container::pointer>::__value), |
962 | _Container>::__type>& __i) _GLIBCXX_NOEXCEPTnoexcept |
963 | : _M_current(__i.base()) { } |
964 | |
965 | // Forward iterator requirements |
966 | _GLIBCXX20_CONSTEXPR |
967 | reference |
968 | operator*() const _GLIBCXX_NOEXCEPTnoexcept |
969 | { return *_M_current; } |
970 | |
971 | _GLIBCXX20_CONSTEXPR |
972 | pointer |
973 | operator->() const _GLIBCXX_NOEXCEPTnoexcept |
974 | { return _M_current; } |
975 | |
976 | _GLIBCXX20_CONSTEXPR |
977 | __normal_iterator& |
978 | operator++() _GLIBCXX_NOEXCEPTnoexcept |
979 | { |
980 | ++_M_current; |
981 | return *this; |
982 | } |
983 | |
984 | _GLIBCXX20_CONSTEXPR |
985 | __normal_iterator |
986 | operator++(int) _GLIBCXX_NOEXCEPTnoexcept |
987 | { return __normal_iterator(_M_current++); } |
988 | |
989 | // Bidirectional iterator requirements |
990 | _GLIBCXX20_CONSTEXPR |
991 | __normal_iterator& |
992 | operator--() _GLIBCXX_NOEXCEPTnoexcept |
993 | { |
994 | --_M_current; |
995 | return *this; |
996 | } |
997 | |
998 | _GLIBCXX20_CONSTEXPR |
999 | __normal_iterator |
1000 | operator--(int) _GLIBCXX_NOEXCEPTnoexcept |
1001 | { return __normal_iterator(_M_current--); } |
1002 | |
1003 | // Random access iterator requirements |
1004 | _GLIBCXX20_CONSTEXPR |
1005 | reference |
1006 | operator[](difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1007 | { return _M_current[__n]; } |
1008 | |
1009 | _GLIBCXX20_CONSTEXPR |
1010 | __normal_iterator& |
1011 | operator+=(difference_type __n) _GLIBCXX_NOEXCEPTnoexcept |
1012 | { _M_current += __n; return *this; } |
1013 | |
1014 | _GLIBCXX20_CONSTEXPR |
1015 | __normal_iterator |
1016 | operator+(difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1017 | { return __normal_iterator(_M_current + __n); } |
1018 | |
1019 | _GLIBCXX20_CONSTEXPR |
1020 | __normal_iterator& |
1021 | operator-=(difference_type __n) _GLIBCXX_NOEXCEPTnoexcept |
1022 | { _M_current -= __n; return *this; } |
1023 | |
1024 | _GLIBCXX20_CONSTEXPR |
1025 | __normal_iterator |
1026 | operator-(difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1027 | { return __normal_iterator(_M_current - __n); } |
1028 | |
1029 | _GLIBCXX20_CONSTEXPR |
1030 | const _Iterator& |
1031 | base() const _GLIBCXX_NOEXCEPTnoexcept |
1032 | { return _M_current; } |
1033 | }; |
1034 | |
1035 | // Note: In what follows, the left- and right-hand-side iterators are |
1036 | // allowed to vary in types (conceptually in cv-qualification) so that |
1037 | // comparison between cv-qualified and non-cv-qualified iterators be |
1038 | // valid. However, the greedy and unfriendly operators in std::rel_ops |
1039 | // will make overload resolution ambiguous (when in scope) if we don't |
1040 | // provide overloads whose operands are of the same type. Can someone |
1041 | // remind me what generic programming is about? -- Gaby |
1042 | |
1043 | #if __cpp_lib_three_way_comparison |
1044 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1045 | requires requires (_IteratorL __lhs, _IteratorR __rhs) |
1046 | { { __lhs == __rhs } -> std::convertible_to<bool>; } |
1047 | constexpr bool |
1048 | operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1049 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1050 | noexcept(noexcept(__lhs.base() == __rhs.base())) |
1051 | { return __lhs.base() == __rhs.base(); } |
1052 | |
1053 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1054 | constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL> |
1055 | operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1056 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1057 | noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) |
1058 | { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } |
1059 | #else |
1060 | // Forward iterator requirements |
1061 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1062 | _GLIBCXX20_CONSTEXPR |
1063 | inline bool |
1064 | operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1065 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1066 | _GLIBCXX_NOEXCEPTnoexcept |
1067 | { return __lhs.base() == __rhs.base(); } |
1068 | |
1069 | template<typename _Iterator, typename _Container> |
1070 | _GLIBCXX20_CONSTEXPR |
1071 | inline bool |
1072 | operator==(const __normal_iterator<_Iterator, _Container>& __lhs, |
1073 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1074 | _GLIBCXX_NOEXCEPTnoexcept |
1075 | { return __lhs.base() == __rhs.base(); } |
1076 | |
1077 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1078 | _GLIBCXX20_CONSTEXPR |
1079 | inline bool |
1080 | operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1081 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1082 | _GLIBCXX_NOEXCEPTnoexcept |
1083 | { return __lhs.base() != __rhs.base(); } |
1084 | |
1085 | template<typename _Iterator, typename _Container> |
1086 | _GLIBCXX20_CONSTEXPR |
1087 | inline bool |
1088 | operator!=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1089 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1090 | _GLIBCXX_NOEXCEPTnoexcept |
1091 | { return __lhs.base() != __rhs.base(); } |
1092 | |
1093 | // Random access iterator requirements |
1094 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1095 | inline bool |
1096 | operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1097 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1098 | _GLIBCXX_NOEXCEPTnoexcept |
1099 | { return __lhs.base() < __rhs.base(); } |
1100 | |
1101 | template<typename _Iterator, typename _Container> |
1102 | _GLIBCXX20_CONSTEXPR |
1103 | inline bool |
1104 | operator<(const __normal_iterator<_Iterator, _Container>& __lhs, |
1105 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1106 | _GLIBCXX_NOEXCEPTnoexcept |
1107 | { return __lhs.base() < __rhs.base(); } |
1108 | |
1109 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1110 | inline bool |
1111 | operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1112 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1113 | _GLIBCXX_NOEXCEPTnoexcept |
1114 | { return __lhs.base() > __rhs.base(); } |
1115 | |
1116 | template<typename _Iterator, typename _Container> |
1117 | _GLIBCXX20_CONSTEXPR |
1118 | inline bool |
1119 | operator>(const __normal_iterator<_Iterator, _Container>& __lhs, |
1120 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1121 | _GLIBCXX_NOEXCEPTnoexcept |
1122 | { return __lhs.base() > __rhs.base(); } |
1123 | |
1124 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1125 | inline bool |
1126 | operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1127 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1128 | _GLIBCXX_NOEXCEPTnoexcept |
1129 | { return __lhs.base() <= __rhs.base(); } |
1130 | |
1131 | template<typename _Iterator, typename _Container> |
1132 | _GLIBCXX20_CONSTEXPR |
1133 | inline bool |
1134 | operator<=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1135 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1136 | _GLIBCXX_NOEXCEPTnoexcept |
1137 | { return __lhs.base() <= __rhs.base(); } |
1138 | |
1139 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1140 | inline bool |
1141 | operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1142 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1143 | _GLIBCXX_NOEXCEPTnoexcept |
1144 | { return __lhs.base() >= __rhs.base(); } |
1145 | |
1146 | template<typename _Iterator, typename _Container> |
1147 | _GLIBCXX20_CONSTEXPR |
1148 | inline bool |
1149 | operator>=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1150 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1151 | _GLIBCXX_NOEXCEPTnoexcept |
1152 | { return __lhs.base() >= __rhs.base(); } |
1153 | #endif // three-way comparison |
1154 | |
1155 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1156 | // According to the resolution of DR179 not only the various comparison |
1157 | // operators but also operator- must accept mixed iterator/const_iterator |
1158 | // parameters. |
1159 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1160 | #if __cplusplus201703L >= 201103L |
1161 | // DR 685. |
1162 | _GLIBCXX20_CONSTEXPR |
1163 | inline auto |
1164 | operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1165 | const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept |
1166 | -> decltype(__lhs.base() - __rhs.base()) |
1167 | #else |
1168 | inline typename __normal_iterator<_IteratorL, _Container>::difference_type |
1169 | operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1170 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1171 | #endif |
1172 | { return __lhs.base() - __rhs.base(); } |
1173 | |
1174 | template<typename _Iterator, typename _Container> |
1175 | _GLIBCXX20_CONSTEXPR |
1176 | inline typename __normal_iterator<_Iterator, _Container>::difference_type |
1177 | operator-(const __normal_iterator<_Iterator, _Container>& __lhs, |
1178 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1179 | _GLIBCXX_NOEXCEPTnoexcept |
1180 | { return __lhs.base() - __rhs.base(); } |
1181 | |
1182 | template<typename _Iterator, typename _Container> |
1183 | _GLIBCXX20_CONSTEXPR |
1184 | inline __normal_iterator<_Iterator, _Container> |
1185 | operator+(typename __normal_iterator<_Iterator, _Container>::difference_type |
1186 | __n, const __normal_iterator<_Iterator, _Container>& __i) |
1187 | _GLIBCXX_NOEXCEPTnoexcept |
1188 | { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); } |
1189 | |
1190 | _GLIBCXX_END_NAMESPACE_VERSION |
1191 | } // namespace |
1192 | |
1193 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
1194 | { |
1195 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
1196 | |
1197 | template<typename _Iterator, typename _Container> |
1198 | _GLIBCXX20_CONSTEXPR |
1199 | _Iterator |
1200 | __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) |
1201 | _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)noexcept(std::is_nothrow_copy_constructible<_Iterator>:: value) |
1202 | { return __it.base(); } |
1203 | |
1204 | #if __cplusplus201703L >= 201103L |
1205 | /** |
1206 | * @addtogroup iterators |
1207 | * @{ |
1208 | */ |
1209 | |
1210 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1211 | template<semiregular _Sent> |
1212 | class move_sentinel |
1213 | { |
1214 | public: |
1215 | constexpr |
1216 | move_sentinel() |
1217 | noexcept(is_nothrow_default_constructible_v<_Sent>) |
1218 | : _M_last() { } |
1219 | |
1220 | constexpr explicit |
1221 | move_sentinel(_Sent __s) |
1222 | noexcept(is_nothrow_move_constructible_v<_Sent>) |
1223 | : _M_last(std::move(__s)) { } |
1224 | |
1225 | template<typename _S2> requires convertible_to<const _S2&, _Sent> |
1226 | constexpr |
1227 | move_sentinel(const move_sentinel<_S2>& __s) |
1228 | noexcept(is_nothrow_constructible_v<_Sent, const _S2&>) |
1229 | : _M_last(__s.base()) |
1230 | { } |
1231 | |
1232 | template<typename _S2> requires assignable_from<_Sent&, const _S2&> |
1233 | constexpr move_sentinel& |
1234 | operator=(const move_sentinel<_S2>& __s) |
1235 | noexcept(is_nothrow_assignable_v<_Sent, const _S2&>) |
1236 | { |
1237 | _M_last = __s.base(); |
1238 | return *this; |
1239 | } |
1240 | |
1241 | constexpr _Sent |
1242 | base() const |
1243 | noexcept(is_nothrow_copy_constructible_v<_Sent>) |
1244 | { return _M_last; } |
1245 | |
1246 | private: |
1247 | _Sent _M_last; |
1248 | }; |
1249 | #endif // C++20 |
1250 | |
1251 | // 24.4.3 Move iterators |
1252 | /** |
1253 | * Class template move_iterator is an iterator adapter with the same |
1254 | * behavior as the underlying iterator except that its dereference |
1255 | * operator implicitly converts the value returned by the underlying |
1256 | * iterator's dereference operator to an rvalue reference. Some |
1257 | * generic algorithms can be called with move iterators to replace |
1258 | * copying with moving. |
1259 | */ |
1260 | template<typename _Iterator> |
1261 | class move_iterator |
1262 | { |
1263 | _Iterator _M_current; |
1264 | |
1265 | using __traits_type = iterator_traits<_Iterator>; |
1266 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1267 | using __base_cat = typename __traits_type::iterator_category; |
1268 | #else |
1269 | using __base_ref = typename __traits_type::reference; |
1270 | #endif |
1271 | |
1272 | public: |
1273 | using iterator_type = _Iterator; |
1274 | |
1275 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1276 | using iterator_concept = input_iterator_tag; |
1277 | using iterator_category |
1278 | = __detail::__clamp_iter_cat<__base_cat, random_access_iterator_tag>; |
1279 | using value_type = iter_value_t<_Iterator>; |
1280 | using difference_type = iter_difference_t<_Iterator>; |
1281 | using pointer = _Iterator; |
1282 | using reference = iter_rvalue_reference_t<_Iterator>; |
1283 | #else |
1284 | typedef typename __traits_type::iterator_category iterator_category; |
1285 | typedef typename __traits_type::value_type value_type; |
1286 | typedef typename __traits_type::difference_type difference_type; |
1287 | // NB: DR 680. |
1288 | typedef _Iterator pointer; |
1289 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1290 | // 2106. move_iterator wrapping iterators returning prvalues |
1291 | typedef typename conditional<is_reference<__base_ref>::value, |
1292 | typename remove_reference<__base_ref>::type&&, |
1293 | __base_ref>::type reference; |
1294 | #endif |
1295 | |
1296 | _GLIBCXX17_CONSTEXPRconstexpr |
1297 | move_iterator() |
1298 | : _M_current() { } |
1299 | |
1300 | explicit _GLIBCXX17_CONSTEXPRconstexpr |
1301 | move_iterator(iterator_type __i) |
1302 | : _M_current(std::move(__i)) { } |
1303 | |
1304 | template<typename _Iter> |
1305 | _GLIBCXX17_CONSTEXPRconstexpr |
1306 | move_iterator(const move_iterator<_Iter>& __i) |
1307 | : _M_current(__i.base()) { } |
1308 | |
1309 | #if __cplusplus201703L <= 201703L |
1310 | _GLIBCXX17_CONSTEXPRconstexpr iterator_type |
1311 | base() const |
1312 | { return _M_current; } |
1313 | #else |
1314 | constexpr iterator_type |
1315 | base() const & |
1316 | #if __cpp_lib_concepts |
1317 | requires copy_constructible<iterator_type> |
1318 | #endif |
1319 | { return _M_current; } |
1320 | |
1321 | constexpr iterator_type |
1322 | base() && |
1323 | { return std::move(_M_current); } |
1324 | #endif |
1325 | |
1326 | _GLIBCXX17_CONSTEXPRconstexpr reference |
1327 | operator*() const |
1328 | { return static_cast<reference>(*_M_current); } |
1329 | |
1330 | _GLIBCXX17_CONSTEXPRconstexpr pointer |
1331 | operator->() const |
1332 | { return _M_current; } |
1333 | |
1334 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1335 | operator++() |
1336 | { |
1337 | ++_M_current; |
1338 | return *this; |
1339 | } |
1340 | |
1341 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1342 | operator++(int) |
1343 | { |
1344 | move_iterator __tmp = *this; |
1345 | ++_M_current; |
1346 | return __tmp; |
1347 | } |
1348 | |
1349 | #if __cpp_lib_concepts |
1350 | constexpr void |
1351 | operator++(int) requires (!forward_iterator<_Iterator>) |
1352 | { ++_M_current; } |
1353 | #endif |
1354 | |
1355 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1356 | operator--() |
1357 | { |
1358 | --_M_current; |
1359 | return *this; |
1360 | } |
1361 | |
1362 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1363 | operator--(int) |
1364 | { |
1365 | move_iterator __tmp = *this; |
1366 | --_M_current; |
1367 | return __tmp; |
1368 | } |
1369 | |
1370 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1371 | operator+(difference_type __n) const |
1372 | { return move_iterator(_M_current + __n); } |
1373 | |
1374 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1375 | operator+=(difference_type __n) |
1376 | { |
1377 | _M_current += __n; |
1378 | return *this; |
1379 | } |
1380 | |
1381 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1382 | operator-(difference_type __n) const |
1383 | { return move_iterator(_M_current - __n); } |
1384 | |
1385 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1386 | operator-=(difference_type __n) |
1387 | { |
1388 | _M_current -= __n; |
1389 | return *this; |
1390 | } |
1391 | |
1392 | _GLIBCXX17_CONSTEXPRconstexpr reference |
1393 | operator[](difference_type __n) const |
1394 | { return std::move(_M_current[__n]); } |
1395 | |
1396 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1397 | template<sentinel_for<_Iterator> _Sent> |
1398 | friend constexpr bool |
1399 | operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) |
1400 | { return __x.base() == __y.base(); } |
1401 | |
1402 | template<sized_sentinel_for<_Iterator> _Sent> |
1403 | friend constexpr iter_difference_t<_Iterator> |
1404 | operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) |
1405 | { return __x.base() - __y.base(); } |
1406 | |
1407 | template<sized_sentinel_for<_Iterator> _Sent> |
1408 | friend constexpr iter_difference_t<_Iterator> |
1409 | operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) |
1410 | { return __x.base() - __y.base(); } |
1411 | |
1412 | friend constexpr iter_rvalue_reference_t<_Iterator> |
1413 | iter_move(const move_iterator& __i) |
1414 | noexcept(noexcept(ranges::iter_move(__i._M_current))) |
1415 | { return ranges::iter_move(__i._M_current); } |
1416 | |
1417 | template<indirectly_swappable<_Iterator> _Iter2> |
1418 | friend constexpr void |
1419 | iter_swap(const move_iterator& __x, const move_iterator<_Iter2>& __y) |
1420 | noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) |
1421 | { return ranges::iter_swap(__x._M_current, __y._M_current); } |
1422 | #endif // C++20 |
1423 | }; |
1424 | |
1425 | template<typename _IteratorL, typename _IteratorR> |
1426 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1427 | operator==(const move_iterator<_IteratorL>& __x, |
1428 | const move_iterator<_IteratorR>& __y) |
1429 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1430 | requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; } |
1431 | #endif |
1432 | { return __x.base() == __y.base(); } |
1433 | |
1434 | #if __cpp_lib_three_way_comparison |
1435 | template<typename _IteratorL, |
1436 | three_way_comparable_with<_IteratorL> _IteratorR> |
1437 | constexpr compare_three_way_result_t<_IteratorL, _IteratorR> |
1438 | operator<=>(const move_iterator<_IteratorL>& __x, |
1439 | const move_iterator<_IteratorR>& __y) |
1440 | { return __x.base() <=> __y.base(); } |
1441 | #else |
1442 | template<typename _IteratorL, typename _IteratorR> |
1443 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1444 | operator!=(const move_iterator<_IteratorL>& __x, |
1445 | const move_iterator<_IteratorR>& __y) |
1446 | { return !(__x == __y); } |
1447 | #endif |
1448 | |
1449 | template<typename _IteratorL, typename _IteratorR> |
1450 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1451 | operator<(const move_iterator<_IteratorL>& __x, |
1452 | const move_iterator<_IteratorR>& __y) |
1453 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1454 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
1455 | #endif |
1456 | { return __x.base() < __y.base(); } |
1457 | |
1458 | template<typename _IteratorL, typename _IteratorR> |
1459 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1460 | operator<=(const move_iterator<_IteratorL>& __x, |
1461 | const move_iterator<_IteratorR>& __y) |
1462 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1463 | requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; } |
1464 | #endif |
1465 | { return !(__y < __x); } |
1466 | |
1467 | template<typename _IteratorL, typename _IteratorR> |
1468 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1469 | operator>(const move_iterator<_IteratorL>& __x, |
1470 | const move_iterator<_IteratorR>& __y) |
1471 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1472 | requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; } |
1473 | #endif |
1474 | { return __y < __x; } |
1475 | |
1476 | template<typename _IteratorL, typename _IteratorR> |
1477 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1478 | operator>=(const move_iterator<_IteratorL>& __x, |
1479 | const move_iterator<_IteratorR>& __y) |
1480 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1481 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
1482 | #endif |
1483 | { return !(__x < __y); } |
1484 | |
1485 | #if ! (__cplusplus201703L > 201703L && __cpp_lib_concepts) |
1486 | // Note: See __normal_iterator operators note from Gaby to understand |
1487 | // why we have these extra overloads for some move_iterator operators. |
1488 | |
1489 | // These extra overloads are not needed in C++20, because the ones above |
1490 | // are constrained with a requires-clause and so overload resolution will |
1491 | // prefer them to greedy unconstrained function templates. |
1492 | |
1493 | template<typename _Iterator> |
1494 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1495 | operator==(const move_iterator<_Iterator>& __x, |
1496 | const move_iterator<_Iterator>& __y) |
1497 | { return __x.base() == __y.base(); } |
1498 | |
1499 | template<typename _Iterator> |
1500 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1501 | operator!=(const move_iterator<_Iterator>& __x, |
1502 | const move_iterator<_Iterator>& __y) |
1503 | { return !(__x == __y); } |
1504 | |
1505 | template<typename _Iterator> |
1506 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1507 | operator<(const move_iterator<_Iterator>& __x, |
1508 | const move_iterator<_Iterator>& __y) |
1509 | { return __x.base() < __y.base(); } |
1510 | |
1511 | template<typename _Iterator> |
1512 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1513 | operator<=(const move_iterator<_Iterator>& __x, |
1514 | const move_iterator<_Iterator>& __y) |
1515 | { return !(__y < __x); } |
1516 | |
1517 | template<typename _Iterator> |
1518 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1519 | operator>(const move_iterator<_Iterator>& __x, |
1520 | const move_iterator<_Iterator>& __y) |
1521 | { return __y < __x; } |
1522 | |
1523 | template<typename _Iterator> |
1524 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1525 | operator>=(const move_iterator<_Iterator>& __x, |
1526 | const move_iterator<_Iterator>& __y) |
1527 | { return !(__x < __y); } |
1528 | #endif // ! C++20 |
1529 | |
1530 | // DR 685. |
1531 | template<typename _IteratorL, typename _IteratorR> |
1532 | inline _GLIBCXX17_CONSTEXPRconstexpr auto |
1533 | operator-(const move_iterator<_IteratorL>& __x, |
1534 | const move_iterator<_IteratorR>& __y) |
1535 | -> decltype(__x.base() - __y.base()) |
1536 | { return __x.base() - __y.base(); } |
1537 | |
1538 | template<typename _Iterator> |
1539 | inline _GLIBCXX17_CONSTEXPRconstexpr move_iterator<_Iterator> |
1540 | operator+(typename move_iterator<_Iterator>::difference_type __n, |
1541 | const move_iterator<_Iterator>& __x) |
1542 | { return __x + __n; } |
1543 | |
1544 | template<typename _Iterator> |
1545 | inline _GLIBCXX17_CONSTEXPRconstexpr move_iterator<_Iterator> |
1546 | make_move_iterator(_Iterator __i) |
1547 | { return move_iterator<_Iterator>(std::move(__i)); } |
1548 | |
1549 | template<typename _Iterator, typename _ReturnType |
1550 | = typename conditional<__move_if_noexcept_cond |
1551 | <typename iterator_traits<_Iterator>::value_type>::value, |
1552 | _Iterator, move_iterator<_Iterator>>::type> |
1553 | inline _GLIBCXX17_CONSTEXPRconstexpr _ReturnType |
1554 | __make_move_if_noexcept_iterator(_Iterator __i) |
1555 | { return _ReturnType(__i); } |
1556 | |
1557 | // Overload for pointers that matches std::move_if_noexcept more closely, |
1558 | // returning a constant iterator when we don't want to move. |
1559 | template<typename _Tp, typename _ReturnType |
1560 | = typename conditional<__move_if_noexcept_cond<_Tp>::value, |
1561 | const _Tp*, move_iterator<_Tp*>>::type> |
1562 | inline _GLIBCXX17_CONSTEXPRconstexpr _ReturnType |
1563 | __make_move_if_noexcept_iterator(_Tp* __i) |
1564 | { return _ReturnType(__i); } |
1565 | |
1566 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1567 | // [iterators.common] Common iterators |
1568 | |
1569 | namespace __detail |
1570 | { |
1571 | template<typename _It> |
1572 | concept __common_iter_has_arrow = indirectly_readable<const _It> |
1573 | && (requires(const _It& __it) { __it.operator->(); } |
1574 | || is_reference_v<iter_reference_t<_It>> |
1575 | || constructible_from<iter_value_t<_It>, iter_reference_t<_It>>); |
1576 | |
1577 | } // namespace __detail |
1578 | |
1579 | /// An iterator/sentinel adaptor for representing a non-common range. |
1580 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
1581 | requires (!same_as<_It, _Sent>) && copyable<_It> |
1582 | class common_iterator |
1583 | { |
1584 | template<typename _Tp, typename _Up> |
1585 | static constexpr bool |
1586 | _S_noexcept1() |
1587 | { |
1588 | if constexpr (is_trivially_default_constructible_v<_Tp>) |
1589 | return is_nothrow_assignable_v<_Tp, _Up>; |
1590 | else |
1591 | return is_nothrow_constructible_v<_Tp, _Up>; |
1592 | } |
1593 | |
1594 | template<typename _It2, typename _Sent2> |
1595 | static constexpr bool |
1596 | _S_noexcept() |
1597 | { return _S_noexcept1<_It, _It2>() && _S_noexcept1<_Sent, _Sent2>(); } |
1598 | |
1599 | class _Proxy |
1600 | { |
1601 | iter_value_t<_It> _M_keep; |
1602 | |
1603 | _Proxy(iter_reference_t<_It>&& __x) |
1604 | : _M_keep(std::move(__x)) { } |
1605 | |
1606 | friend class common_iterator; |
1607 | |
1608 | public: |
1609 | const iter_value_t<_It>* |
1610 | operator->() const |
1611 | { return std::__addressof(_M_keep); } |
1612 | }; |
1613 | |
1614 | public: |
1615 | constexpr |
1616 | common_iterator() |
1617 | noexcept(is_nothrow_default_constructible_v<_It>) |
1618 | : _M_it(), _M_index(0) |
1619 | { } |
1620 | |
1621 | constexpr |
1622 | common_iterator(_It __i) |
1623 | noexcept(is_nothrow_move_constructible_v<_It>) |
1624 | : _M_it(std::move(__i)), _M_index(0) |
1625 | { } |
1626 | |
1627 | constexpr |
1628 | common_iterator(_Sent __s) |
1629 | noexcept(is_nothrow_move_constructible_v<_Sent>) |
1630 | : _M_sent(std::move(__s)), _M_index(1) |
1631 | { } |
1632 | |
1633 | template<typename _It2, typename _Sent2> |
1634 | requires convertible_to<const _It2&, _It> |
1635 | && convertible_to<const _Sent2&, _Sent> |
1636 | constexpr |
1637 | common_iterator(const common_iterator<_It2, _Sent2>& __x) |
1638 | noexcept(_S_noexcept<const _It2&, const _Sent2&>()) |
1639 | : _M_valueless(), _M_index(__x._M_index) |
1640 | { |
1641 | if (_M_index == 0) |
1642 | { |
1643 | if constexpr (is_trivially_default_constructible_v<_It>) |
1644 | _M_it = std::move(__x._M_it); |
1645 | else |
1646 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1647 | } |
1648 | else if (_M_index == 1) |
1649 | { |
1650 | if constexpr (is_trivially_default_constructible_v<_Sent>) |
1651 | _M_sent = std::move(__x._M_sent); |
1652 | else |
1653 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1654 | } |
1655 | } |
1656 | |
1657 | constexpr |
1658 | common_iterator(const common_iterator& __x) |
1659 | noexcept(_S_noexcept<const _It&, const _Sent&>()) |
1660 | : _M_valueless(), _M_index(__x._M_index) |
1661 | { |
1662 | if (_M_index == 0) |
1663 | { |
1664 | if constexpr (is_trivially_default_constructible_v<_It>) |
1665 | _M_it = std::move(__x._M_it); |
1666 | else |
1667 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1668 | } |
1669 | else if (_M_index == 1) |
1670 | { |
1671 | if constexpr (is_trivially_default_constructible_v<_Sent>) |
1672 | _M_sent = std::move(__x._M_sent); |
1673 | else |
1674 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1675 | } |
1676 | } |
1677 | |
1678 | common_iterator& |
1679 | operator=(const common_iterator& __x) |
1680 | noexcept(is_nothrow_copy_assignable_v<_It> |
1681 | && is_nothrow_copy_assignable_v<_Sent> |
1682 | && is_nothrow_copy_constructible_v<_It> |
1683 | && is_nothrow_copy_constructible_v<_Sent>) |
1684 | { |
1685 | return this->operator=<_It, _Sent>(__x); |
1686 | } |
1687 | |
1688 | template<typename _It2, typename _Sent2> |
1689 | requires convertible_to<const _It2&, _It> |
1690 | && convertible_to<const _Sent2&, _Sent> |
1691 | && assignable_from<_It&, const _It2&> |
1692 | && assignable_from<_Sent&, const _Sent2&> |
1693 | common_iterator& |
1694 | operator=(const common_iterator<_It2, _Sent2>& __x) |
1695 | noexcept(is_nothrow_constructible_v<_It, const _It2&> |
1696 | && is_nothrow_constructible_v<_Sent, const _Sent2&> |
1697 | && is_nothrow_assignable_v<_It, const _It2&> |
1698 | && is_nothrow_assignable_v<_Sent, const _Sent2&>) |
1699 | { |
1700 | switch(_M_index << 2 | __x._M_index) |
1701 | { |
1702 | case 0b0000: |
1703 | _M_it = __x._M_it; |
1704 | break; |
1705 | case 0b0101: |
1706 | _M_sent = __x._M_sent; |
1707 | break; |
1708 | case 0b0001: |
1709 | _M_it.~_It(); |
1710 | _M_index = -1; |
1711 | [[fallthrough]]; |
1712 | case 0b1001: |
1713 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1714 | _M_index = 1; |
1715 | break; |
1716 | case 0b0100: |
1717 | _M_sent.~_Sent(); |
1718 | _M_index = -1; |
1719 | [[fallthrough]]; |
1720 | case 0b1000: |
1721 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1722 | _M_index = 0; |
1723 | break; |
1724 | default: |
1725 | __glibcxx_assert(__x._M_has_value()); |
1726 | __builtin_unreachable(); |
1727 | } |
1728 | return *this; |
1729 | } |
1730 | |
1731 | ~common_iterator() |
1732 | { |
1733 | switch (_M_index) |
1734 | { |
1735 | case 0: |
1736 | _M_it.~_It(); |
1737 | break; |
1738 | case 1: |
1739 | _M_sent.~_Sent(); |
1740 | break; |
1741 | } |
1742 | } |
1743 | |
1744 | decltype(auto) |
1745 | operator*() |
1746 | { |
1747 | __glibcxx_assert(_M_index == 0); |
1748 | return *_M_it; |
1749 | } |
1750 | |
1751 | decltype(auto) |
1752 | operator*() const requires __detail::__dereferenceable<const _It> |
1753 | { |
1754 | __glibcxx_assert(_M_index == 0); |
1755 | return *_M_it; |
1756 | } |
1757 | |
1758 | decltype(auto) |
1759 | operator->() const requires __detail::__common_iter_has_arrow<_It> |
1760 | { |
1761 | __glibcxx_assert(_M_index == 0); |
1762 | if constexpr (is_pointer_v<_It> || requires { _M_it.operator->(); }) |
1763 | return _M_it; |
1764 | else if constexpr (is_reference_v<iter_reference_t<_It>>) |
1765 | { |
1766 | auto&& __tmp = *_M_it; |
1767 | return std::__addressof(__tmp); |
1768 | } |
1769 | else |
1770 | return _Proxy{*_M_it}; |
1771 | } |
1772 | |
1773 | common_iterator& |
1774 | operator++() |
1775 | { |
1776 | __glibcxx_assert(_M_index == 0); |
1777 | ++_M_it; |
1778 | return *this; |
1779 | } |
1780 | |
1781 | decltype(auto) |
1782 | operator++(int) |
1783 | { |
1784 | __glibcxx_assert(_M_index == 0); |
1785 | if constexpr (forward_iterator<_It>) |
1786 | { |
1787 | common_iterator __tmp = *this; |
1788 | ++*this; |
1789 | return __tmp; |
1790 | } |
1791 | else |
1792 | return _M_it++; |
1793 | } |
1794 | |
1795 | template<typename _It2, sentinel_for<_It> _Sent2> |
1796 | requires sentinel_for<_Sent, _It2> |
1797 | friend bool |
1798 | operator==(const common_iterator& __x, |
1799 | const common_iterator<_It2, _Sent2>& __y) |
1800 | { |
1801 | switch(__x._M_index << 2 | __y._M_index) |
1802 | { |
1803 | case 0b0000: |
1804 | case 0b0101: |
1805 | return true; |
1806 | case 0b0001: |
1807 | return __x._M_it == __y._M_sent; |
1808 | case 0b0100: |
1809 | return __x._M_sent == __y._M_it; |
1810 | default: |
1811 | __glibcxx_assert(__x._M_has_value()); |
1812 | __glibcxx_assert(__y._M_has_value()); |
1813 | __builtin_unreachable(); |
1814 | } |
1815 | } |
1816 | |
1817 | template<typename _It2, sentinel_for<_It> _Sent2> |
1818 | requires sentinel_for<_Sent, _It2> && equality_comparable_with<_It, _It2> |
1819 | friend bool |
1820 | operator==(const common_iterator& __x, |
1821 | const common_iterator<_It2, _Sent2>& __y) |
1822 | { |
1823 | switch(__x._M_index << 2 | __y._M_index) |
1824 | { |
1825 | case 0b0101: |
1826 | return true; |
1827 | case 0b0000: |
1828 | return __x._M_it == __y._M_it; |
1829 | case 0b0001: |
1830 | return __x._M_it == __y._M_sent; |
1831 | case 0b0100: |
1832 | return __x._M_sent == __y._M_it; |
1833 | default: |
1834 | __glibcxx_assert(__x._M_has_value()); |
1835 | __glibcxx_assert(__y._M_has_value()); |
1836 | __builtin_unreachable(); |
1837 | } |
1838 | } |
1839 | |
1840 | template<sized_sentinel_for<_It> _It2, sized_sentinel_for<_It> _Sent2> |
1841 | requires sized_sentinel_for<_Sent, _It2> |
1842 | friend iter_difference_t<_It2> |
1843 | operator-(const common_iterator& __x, |
1844 | const common_iterator<_It2, _Sent2>& __y) |
1845 | { |
1846 | switch(__x._M_index << 2 | __y._M_index) |
1847 | { |
1848 | case 0b0101: |
1849 | return 0; |
1850 | case 0b0000: |
1851 | return __x._M_it - __y._M_it; |
1852 | case 0b0001: |
1853 | return __x._M_it - __y._M_sent; |
1854 | case 0b0100: |
1855 | return __x._M_sent - __y._M_it; |
1856 | default: |
1857 | __glibcxx_assert(__x._M_has_value()); |
1858 | __glibcxx_assert(__y._M_has_value()); |
1859 | __builtin_unreachable(); |
1860 | } |
1861 | } |
1862 | |
1863 | friend iter_rvalue_reference_t<_It> |
1864 | iter_move(const common_iterator& __i) |
1865 | noexcept(noexcept(ranges::iter_move(std::declval<const _It&>()))) |
1866 | requires input_iterator<_It> |
1867 | { |
1868 | __glibcxx_assert(__i._M_index == 0); |
1869 | return ranges::iter_move(__i._M_it); |
1870 | } |
1871 | |
1872 | template<indirectly_swappable<_It> _It2, typename _Sent2> |
1873 | friend void |
1874 | iter_swap(const common_iterator& __x, |
1875 | const common_iterator<_It2, _Sent2>& __y) |
1876 | noexcept(noexcept(ranges::iter_swap(std::declval<const _It&>(), |
1877 | std::declval<const _It2&>()))) |
1878 | { |
1879 | __glibcxx_assert(__x._M_index == 0); |
1880 | __glibcxx_assert(__y._M_index == 0); |
1881 | return ranges::iter_swap(__x._M_it, __y._M_it); |
1882 | } |
1883 | |
1884 | private: |
1885 | template<input_or_output_iterator _It2, sentinel_for<_It2> _Sent2> |
1886 | friend class common_iterator; |
1887 | |
1888 | bool _M_has_value() const noexcept { return _M_index < 2; } |
1889 | |
1890 | union |
1891 | { |
1892 | _It _M_it; |
1893 | _Sent _M_sent; |
1894 | unsigned char _M_valueless; |
1895 | }; |
1896 | unsigned char _M_index; // 0==_M_it, 1==_M_sent, 2==valueless |
1897 | }; |
1898 | |
1899 | template<typename _It, typename _Sent> |
1900 | struct incrementable_traits<common_iterator<_It, _Sent>> |
1901 | { |
1902 | using difference_type = iter_difference_t<_It>; |
1903 | }; |
1904 | |
1905 | namespace __detail |
1906 | { |
1907 | // FIXME: This has to be at namespace-scope because of PR 92103. |
1908 | template<typename _It, typename _Sent> |
1909 | struct __common_iter_ptr |
1910 | { |
1911 | using type = void; |
1912 | }; |
1913 | |
1914 | template<typename _It, typename _Sent> |
1915 | requires __detail::__common_iter_has_arrow<_It> |
1916 | struct __common_iter_ptr<_It, _Sent> |
1917 | { |
1918 | using common_iterator = std::common_iterator<_It, _Sent>; |
1919 | |
1920 | using type |
1921 | = decltype(std::declval<const common_iterator&>().operator->()); |
1922 | }; |
1923 | } // namespace __detail |
1924 | |
1925 | template<input_iterator _It, typename _Sent> |
1926 | struct iterator_traits<common_iterator<_It, _Sent>> |
1927 | { |
1928 | using iterator_concept = conditional_t<forward_iterator<_It>, |
1929 | forward_iterator_tag, input_iterator_tag>; |
1930 | using iterator_category = __detail::__clamp_iter_cat< |
1931 | typename iterator_traits<_It>::iterator_category, |
1932 | forward_iterator_tag, input_iterator_tag>; |
1933 | using value_type = iter_value_t<_It>; |
1934 | using difference_type = iter_difference_t<_It>; |
1935 | using pointer = typename __detail::__common_iter_ptr<_It, _Sent>::type; |
1936 | using reference = iter_reference_t<_It>; |
1937 | }; |
1938 | |
1939 | // [iterators.counted] Counted iterators |
1940 | |
1941 | /// An iterator adaptor that keeps track of the distance to the end. |
1942 | template<input_or_output_iterator _It> |
1943 | class counted_iterator |
1944 | { |
1945 | public: |
1946 | using iterator_type = _It; |
1947 | |
1948 | constexpr counted_iterator() = default; |
1949 | |
1950 | constexpr |
1951 | counted_iterator(_It __i, iter_difference_t<_It> __n) |
1952 | : _M_current(std::move(__i)), _M_length(__n) |
1953 | { __glibcxx_assert(__n >= 0); } |
1954 | |
1955 | template<typename _It2> |
1956 | requires convertible_to<const _It2&, _It> |
1957 | constexpr |
1958 | counted_iterator(const counted_iterator<_It2>& __x) |
1959 | : _M_current(__x._M_current), _M_length(__x._M_length) |
1960 | { } |
1961 | |
1962 | template<typename _It2> |
1963 | requires assignable_from<_It&, const _It2&> |
1964 | constexpr counted_iterator& |
1965 | operator=(const counted_iterator<_It2>& __x) |
1966 | { |
1967 | _M_current = __x._M_current; |
1968 | _M_length = __x._M_length; |
1969 | return *this; |
1970 | } |
1971 | |
1972 | constexpr _It |
1973 | base() const & |
1974 | noexcept(is_nothrow_copy_constructible_v<_It>) |
1975 | requires copy_constructible<_It> |
1976 | { return _M_current; } |
1977 | |
1978 | constexpr _It |
1979 | base() && |
1980 | noexcept(is_nothrow_move_constructible_v<_It>) |
1981 | { return std::move(_M_current); } |
1982 | |
1983 | constexpr iter_difference_t<_It> |
1984 | count() const noexcept { return _M_length; } |
1985 | |
1986 | constexpr decltype(auto) |
1987 | operator*() |
1988 | noexcept(noexcept(*_M_current)) |
1989 | { return *_M_current; } |
1990 | |
1991 | constexpr decltype(auto) |
1992 | operator*() const |
1993 | noexcept(noexcept(*_M_current)) |
1994 | requires __detail::__dereferenceable<const _It> |
1995 | { return *_M_current; } |
1996 | |
1997 | constexpr counted_iterator& |
1998 | operator++() |
1999 | { |
2000 | __glibcxx_assert(_M_length > 0); |
2001 | ++_M_current; |
2002 | --_M_length; |
2003 | return *this; |
2004 | } |
2005 | |
2006 | decltype(auto) |
2007 | operator++(int) |
2008 | { |
2009 | __glibcxx_assert(_M_length > 0); |
2010 | --_M_length; |
2011 | __trytry |
2012 | { |
2013 | return _M_current++; |
2014 | } __catch(...)catch(...) { |
2015 | ++_M_length; |
2016 | throw; |
2017 | } |
2018 | |
2019 | } |
2020 | |
2021 | constexpr counted_iterator |
2022 | operator++(int) requires forward_iterator<_It> |
2023 | { |
2024 | auto __tmp = *this; |
2025 | ++*this; |
2026 | return __tmp; |
2027 | } |
2028 | |
2029 | constexpr counted_iterator& |
2030 | operator--() requires bidirectional_iterator<_It> |
2031 | { |
2032 | --_M_current; |
2033 | ++_M_length; |
2034 | return *this; |
2035 | } |
2036 | |
2037 | constexpr counted_iterator |
2038 | operator--(int) requires bidirectional_iterator<_It> |
2039 | { |
2040 | auto __tmp = *this; |
2041 | --*this; |
2042 | return __tmp; |
2043 | } |
2044 | |
2045 | constexpr counted_iterator |
2046 | operator+(iter_difference_t<_It> __n) const |
2047 | requires random_access_iterator<_It> |
2048 | { return counted_iterator(_M_current + __n, _M_length - __n); } |
2049 | |
2050 | friend constexpr counted_iterator |
2051 | operator+(iter_difference_t<_It> __n, const counted_iterator& __x) |
2052 | requires random_access_iterator<_It> |
2053 | { return __x + __n; } |
2054 | |
2055 | constexpr counted_iterator& |
2056 | operator+=(iter_difference_t<_It> __n) |
2057 | requires random_access_iterator<_It> |
2058 | { |
2059 | __glibcxx_assert(__n <= _M_length); |
2060 | _M_current += __n; |
2061 | _M_length -= __n; |
2062 | return *this; |
2063 | } |
2064 | |
2065 | constexpr counted_iterator |
2066 | operator-(iter_difference_t<_It> __n) const |
2067 | requires random_access_iterator<_It> |
2068 | { return counted_iterator(_M_current - __n, _M_length + __n); } |
2069 | |
2070 | template<common_with<_It> _It2> |
2071 | friend constexpr iter_difference_t<_It2> |
2072 | operator-(const counted_iterator& __x, |
2073 | const counted_iterator<_It2>& __y) |
2074 | { return __y._M_length - __x._M_length; } |
2075 | |
2076 | friend constexpr iter_difference_t<_It> |
2077 | operator-(const counted_iterator& __x, default_sentinel_t) |
2078 | { return -__x._M_length; } |
2079 | |
2080 | friend constexpr iter_difference_t<_It> |
2081 | operator-(default_sentinel_t, const counted_iterator& __y) |
2082 | { return __y._M_length; } |
2083 | |
2084 | constexpr counted_iterator& |
2085 | operator-=(iter_difference_t<_It> __n) |
2086 | requires random_access_iterator<_It> |
2087 | { |
2088 | __glibcxx_assert(-__n <= _M_length); |
2089 | _M_current -= __n; |
2090 | _M_length += __n; |
2091 | return *this; |
2092 | } |
2093 | |
2094 | constexpr decltype(auto) |
2095 | operator[](iter_difference_t<_It> __n) const |
2096 | noexcept(noexcept(_M_current[__n])) |
2097 | requires random_access_iterator<_It> |
2098 | { |
2099 | __glibcxx_assert(__n < _M_length); |
2100 | return _M_current[__n]; |
2101 | } |
2102 | |
2103 | template<common_with<_It> _It2> |
2104 | friend constexpr bool |
2105 | operator==(const counted_iterator& __x, |
2106 | const counted_iterator<_It2>& __y) |
2107 | { return __x._M_length == __y._M_length; } |
2108 | |
2109 | friend constexpr bool |
2110 | operator==(const counted_iterator& __x, default_sentinel_t) |
2111 | { return __x._M_length == 0; } |
2112 | |
2113 | template<common_with<_It> _It2> |
2114 | friend constexpr strong_ordering |
2115 | operator<=>(const counted_iterator& __x, |
2116 | const counted_iterator<_It2>& __y) |
2117 | { return __y._M_length <=> __x._M_length; } |
2118 | |
2119 | friend constexpr iter_rvalue_reference_t<_It> |
2120 | iter_move(const counted_iterator& __i) |
2121 | noexcept(noexcept(ranges::iter_move(__i._M_current))) |
2122 | requires input_iterator<_It> |
2123 | { return ranges::iter_move(__i._M_current); } |
2124 | |
2125 | template<indirectly_swappable<_It> _It2> |
2126 | friend constexpr void |
2127 | iter_swap(const counted_iterator& __x, |
2128 | const counted_iterator<_It2>& __y) |
2129 | noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) |
2130 | { ranges::iter_swap(__x._M_current, __y._M_current); } |
2131 | |
2132 | private: |
2133 | template<input_or_output_iterator _It2> friend class counted_iterator; |
2134 | |
2135 | _It _M_current = _It(); |
2136 | iter_difference_t<_It> _M_length = 0; |
2137 | }; |
2138 | |
2139 | template<typename _It> |
2140 | struct incrementable_traits<counted_iterator<_It>> |
2141 | { |
2142 | using difference_type = iter_difference_t<_It>; |
2143 | }; |
2144 | |
2145 | template<input_iterator _It> |
2146 | struct iterator_traits<counted_iterator<_It>> : iterator_traits<_It> |
2147 | { |
2148 | using pointer = void; |
2149 | }; |
2150 | #endif // C++20 |
2151 | |
2152 | // @} group iterators |
2153 | |
2154 | template<typename _Iterator> |
2155 | auto |
2156 | __niter_base(move_iterator<_Iterator> __it) |
2157 | -> decltype(make_move_iterator(__niter_base(__it.base()))) |
2158 | { return make_move_iterator(__niter_base(__it.base())); } |
2159 | |
2160 | template<typename _Iterator> |
2161 | struct __is_move_iterator<move_iterator<_Iterator> > |
2162 | { |
2163 | enum { __value = 1 }; |
2164 | typedef __true_type __type; |
2165 | }; |
2166 | |
2167 | template<typename _Iterator> |
2168 | auto |
2169 | __miter_base(move_iterator<_Iterator> __it) |
2170 | -> decltype(__miter_base(__it.base())) |
2171 | { return __miter_base(__it.base()); } |
2172 | |
2173 | #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter)std::make_move_iterator(_Iter) std::make_move_iterator(_Iter) |
2174 | #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter)std::__make_move_if_noexcept_iterator(_Iter) \ |
2175 | std::__make_move_if_noexcept_iterator(_Iter) |
2176 | #else |
2177 | #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter)std::make_move_iterator(_Iter) (_Iter) |
2178 | #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter)std::__make_move_if_noexcept_iterator(_Iter) (_Iter) |
2179 | #endif // C++11 |
2180 | |
2181 | #if __cpp_deduction_guides201703L >= 201606 |
2182 | // These helper traits are used for deduction guides |
2183 | // of associative containers. |
2184 | template<typename _InputIterator> |
2185 | using __iter_key_t = remove_const_t< |
2186 | typename iterator_traits<_InputIterator>::value_type::first_type>; |
2187 | |
2188 | template<typename _InputIterator> |
2189 | using __iter_val_t = |
2190 | typename iterator_traits<_InputIterator>::value_type::second_type; |
2191 | |
2192 | template<typename _T1, typename _T2> |
2193 | struct pair; |
2194 | |
2195 | template<typename _InputIterator> |
2196 | using __iter_to_alloc_t = |
2197 | pair<add_const_t<__iter_key_t<_InputIterator>>, |
2198 | __iter_val_t<_InputIterator>>; |
2199 | #endif // __cpp_deduction_guides |
2200 | |
2201 | _GLIBCXX_END_NAMESPACE_VERSION |
2202 | } // namespace |
2203 | |
2204 | #ifdef _GLIBCXX_DEBUG |
2205 | # include <debug/stl_iterator.h> |
2206 | #endif |
2207 | |
2208 | #endif |