Bug Summary

File:home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx
Warning:line 1630, column 41
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name navigatortree.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SVXCORE_DLLIMPLEMENTATION -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/svx/inc -I /home/maarten/src/libreoffice/core/svx/source/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/svx/sdi -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx

/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx

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 <memory>
21#include <svx/dialmgr.hxx>
22#include <svx/fmshell.hxx>
23#include <svx/fmmodel.hxx>
24#include <svx/fmpage.hxx>
25#include <svx/svdpagv.hxx>
26#include <svx/svditer.hxx>
27
28#include <helpids.h>
29#include <fmexpl.hxx>
30#include <fmshimp.hxx>
31#include <fmservs.hxx>
32#include <fmundo.hxx>
33#include <fmpgeimp.hxx>
34#include <fmobj.hxx>
35#include <fmprop.hxx>
36#include <sal/log.hxx>
37#include <vcl/svapp.hxx>
38#include <sfx2/viewsh.hxx>
39#include <sfx2/dispatch.hxx>
40#include <sfx2/viewfrm.hxx>
41#include <comphelper/processfactory.hxx>
42#include <comphelper/property.hxx>
43#include <comphelper/types.hxx>
44#include <com/sun/star/form/FormComponentType.hpp>
45#include <com/sun/star/sdb/CommandType.hpp>
46#include <com/sun/star/beans/PropertyAttribute.hpp>
47#include <com/sun/star/script/XEventAttacherManager.hpp>
48#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
49#include <com/sun/star/datatransfer/XTransferable.hpp>
50#include <com/sun/star/uno/XComponentContext.hpp>
51#include <svx/sdrpaintwindow.hxx>
52
53#include <svx/strings.hrc>
54#include <tools/diagnose_ex.h>
55#include <svx/svxids.hrc>
56#include <bitmaps.hlst>
57#include <vcl/commandevent.hxx>
58
59namespace svxform
60{
61 #define EXPLORER_SYNC_DELAY200 200
62 // Time (in ms) until explorer synchronizes the view after select or deselect
63
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::form;
68 using namespace ::com::sun::star::awt;
69 using namespace ::com::sun::star::container;
70 using namespace ::com::sun::star::script;
71 using namespace ::com::sun::star::datatransfer;
72 using namespace ::com::sun::star::datatransfer::clipboard;
73 using namespace ::com::sun::star::sdb;
74
75
76 // helper
77
78
79 typedef ::std::map< Reference< XInterface >, SdrObject* > MapModelToShape;
80
81
82 static void collectShapeModelMapping( SdrPage const * _pPage, MapModelToShape& _rMapping )
83 {
84 OSL_ENSURE( _pPage, "collectShapeModelMapping: invalid arg!" )do { if (true && (!(_pPage))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "84" ": "), "%s", "collectShapeModelMapping: invalid arg!"
); } } while (false)
;
85
86 _rMapping.clear();
87
88 SdrObjListIter aIter( _pPage );
89 while ( aIter.IsMore() )
90 {
91 SdrObject* pSdrObject = aIter.Next();
92 FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
93 if ( !pFormObject )
94 continue;
95
96 Reference< XInterface > xNormalizedModel( pFormObject->GetUnoControlModel(), UNO_QUERY );
97 // note that this is normalized (i.e. queried for XInterface explicitly)
98
99 ::std::pair< MapModelToShape::iterator, bool > aPos =
100 _rMapping.emplace( xNormalizedModel, pSdrObject );
101 DBG_ASSERT( aPos.second, "collectShapeModelMapping: model was already existent!" )do { if (true && (!(aPos.second))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "101" ": "), "%s", "collectShapeModelMapping: model was already existent!"
); } } while (false)
;
102 // if this asserts, this would mean we have 2 shapes pointing to the same model
103 }
104 }
105
106 NavigatorTreeDropTarget::NavigatorTreeDropTarget(NavigatorTree& rTreeView)
107 : DropTargetHelper(rTreeView.get_widget().get_drop_target())
108 , m_rTreeView(rTreeView)
109 {
110 }
111
112 sal_Int8 NavigatorTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
113 {
114 sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
115
116 if (nAccept != DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE)
117 {
118 // to enable the autoscroll when we're close to the edges
119 weld::TreeView& rWidget = m_rTreeView.get_widget();
120 rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
121 }
122
123 return nAccept;
124 }
125
126 sal_Int8 NavigatorTreeDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
127 {
128 return m_rTreeView.ExecuteDrop(rEvt);
129 }
130
131 NavigatorTree::NavigatorTree(std::unique_ptr<weld::TreeView> xTreeView)
132 :m_xTreeView(std::move(xTreeView))
133 ,m_aDropTargetHelper(*this)
134 ,m_aControlExchange()
135 ,nEditEvent(nullptr)
136 ,m_sdiState(SDI_DIRTY)
137 ,m_nSelectLock(0)
138 ,m_nFormsSelected(0)
139 ,m_nControlsSelected(0)
140 ,m_nHiddenControls(0)
141 ,m_bDragDataDirty(false)
142 ,m_bPrevSelectionMixed(false)
143 ,m_bRootSelected(false)
144 ,m_bInitialUpdate(true)
145 ,m_bKeyboardCut( false )
146 ,m_bEditing( false )
147 {
148 m_xTreeView->set_help_id(HID_FORM_NAVIGATOR"SVX_HID_FORM_NAVIGATOR");
149
150 m_xTreeView->set_selection_mode(SelectionMode::Multiple);
151
152 m_pNavModel.reset(new NavigatorTreeModel());
153 Clear();
154
155 StartListening( *m_pNavModel );
156
157 m_aSynchronizeTimer.SetInvokeHandler(LINK(this, NavigatorTree, OnSynchronizeTimer)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubOnSynchronizeTimer)
);
158 m_xTreeView->connect_changed(LINK(this, NavigatorTree, OnEntrySelDesel)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubOnEntrySelDesel)
);
159 m_xTreeView->connect_key_press(LINK(this, NavigatorTree, KeyInputHdl)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubKeyInputHdl)
);
160 m_xTreeView->connect_popup_menu(LINK(this, NavigatorTree, PopupMenuHdl)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubPopupMenuHdl)
);
161 m_xTreeView->connect_editing(LINK(this, NavigatorTree, EditingEntryHdl)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubEditingEntryHdl)
,
162 LINK(this, NavigatorTree, EditedEntryHdl)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubEditedEntryHdl)
);
163 m_xTreeView->connect_drag_begin(LINK(this, NavigatorTree, DragBeginHdl)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubDragBeginHdl)
);
164 }
165
166 NavigatorTree::~NavigatorTree()
167 {
168 if( nEditEvent )
169 Application::RemoveUserEvent( nEditEvent );
170
171 if (m_aSynchronizeTimer.IsActive())
172 m_aSynchronizeTimer.Stop();
173
174 DBG_ASSERT(GetNavModel() != nullptr, "NavigatorTree::~NavigatorTree : unexpected : no ExplorerModel")do { if (true && (!(GetNavModel() != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "174" ": "), "%s", "NavigatorTree::~NavigatorTree : unexpected : no ExplorerModel"
); } } while (false)
;
175 EndListening( *m_pNavModel );
176 Clear();
177 m_pNavModel.reset();
178 }
179
180 void NavigatorTree::Clear()
181 {
182 m_pNavModel->Clear();
183 }
184
185 void NavigatorTree::UpdateContent( FmFormShell* pFormShell )
186 {
187 if (m_bInitialUpdate)
188 {
189 GrabFocus();
190 m_bInitialUpdate = false;
191 }
192
193 FmFormShell* pOldShell = GetNavModel()->GetFormShell();
194 FmFormPage* pOldPage = GetNavModel()->GetFormPage();
195 FmFormPage* pNewPage = pFormShell ? pFormShell->GetCurPage() : nullptr;
196
197 if ((pOldShell != pFormShell) || (pOldPage != pNewPage))
198 {
199 // new shell during editing
200 if (IsEditingActive())
201 {
202 m_xTreeView->end_editing();
203 m_bEditing = false;
204 }
205
206 m_bDragDataDirty = true; // as a precaution, although I don't drag
207 }
208 GetNavModel()->UpdateContent( pFormShell );
209
210 // if there is a form, expand root
211 if (m_xRootEntry && !m_xTreeView->get_row_expanded(*m_xRootEntry))
212 m_xTreeView->expand_row(*m_xRootEntry);
213 // if there is EXACTLY ONE form, expand it too
214 if (m_xRootEntry)
215 {
216 std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator(m_xRootEntry.get()));
217 bool bFirst = m_xTreeView->iter_children(*xFirst);
218 if (bFirst)
219 {
220 std::unique_ptr<weld::TreeIter> xSibling(m_xTreeView->make_iterator(xFirst.get()));
221 if (!m_xTreeView->iter_next_sibling(*xSibling))
222 m_xTreeView->expand_row(*xFirst);
223 }
224 }
225 }
226
227 bool NavigatorTree::implAllowExchange( sal_Int8 _nAction, bool* _pHasNonHidden )
228 {
229 bool bCurEntry = m_xTreeView->get_cursor(nullptr);
230 if (!bCurEntry)
231 return false;
232
233 // Information for AcceptDrop and Execute Drop
234 CollectSelectionData(SDI_ALL);
235 if (m_arrCurrentSelection.empty())
236 // nothing to do
237 return false;
238
239 // check whether there are only hidden controls
240 // I may add a format to pCtrlExch
241 bool bHasNonHidden = std::any_of(m_arrCurrentSelection.begin(), m_arrCurrentSelection.end(),
242 [this](const auto& rEntry) {
243 FmEntryData* pCurrent = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rEntry).toInt64());
244 return !IsHiddenControl( pCurrent );
245 });
246
247 if ( bHasNonHidden && ( 0 == ( _nAction & DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE ) ) )
248 // non-hidden controls need to be moved
249 return false;
250
251 if ( _pHasNonHidden )
252 *_pHasNonHidden = bHasNonHidden;
253
254 return true;
255 }
256
257 bool NavigatorTree::implPrepareExchange( sal_Int8 _nAction )
258 {
259 bool bHasNonHidden = false;
260 if ( !implAllowExchange( _nAction, &bHasNonHidden ) )
261 return false;
262
263 m_aControlExchange.prepareDrag();
264 m_aControlExchange->setFocusEntry(m_xTreeView->get_cursor(nullptr));
265
266 for (const auto& rpEntry : m_arrCurrentSelection)
267 m_aControlExchange->addSelectedEntry(m_xTreeView->make_iterator(rpEntry.get()));
268
269 m_aControlExchange->setFormsRoot( GetNavModel()->GetFormPage()->GetForms() );
270 m_aControlExchange->buildPathFormat(m_xTreeView.get(), m_xRootEntry.get());
271
272 if (!bHasNonHidden)
273 {
274 // create a sequence
275 Sequence< Reference< XInterface > > seqIFaces(m_arrCurrentSelection.size());
276 Reference< XInterface >* pArray = seqIFaces.getArray();
277 for (const auto& rpEntry : m_arrCurrentSelection)
278 {
279 *pArray = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rpEntry).toInt64())->GetElement();
280 ++pArray;
281 }
282 // and the new format
283 m_aControlExchange->addHiddenControlsFormat(seqIFaces);
284 }
285
286 m_bDragDataDirty = false;
287 return true;
288 }
289
290 IMPL_LINK(NavigatorTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)bool NavigatorTree::LinkStubDragBeginHdl(void * instance, bool
& data) { return static_cast<NavigatorTree *>(instance
)->DragBeginHdl(data); } bool NavigatorTree::DragBeginHdl(
bool& rUnsetDragIcon)
291 {
292 rUnsetDragIcon = false;
293
294 bool bSuccess = implPrepareExchange(DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
295 if (bSuccess)
296 {
297 OControlExchange& rExchange = *m_aControlExchange;
298 rtl::Reference<TransferDataContainer> xHelper(&rExchange);
299 m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
300 rExchange.setDragging(true);
301 }
302 return !bSuccess;
303 }
304
305 IMPL_LINK(NavigatorTree, PopupMenuHdl, const CommandEvent&, rEvt, bool)bool NavigatorTree::LinkStubPopupMenuHdl(void * instance, const
CommandEvent& data) { return static_cast<NavigatorTree
*>(instance)->PopupMenuHdl(data); } bool NavigatorTree
::PopupMenuHdl(const CommandEvent& rEvt)
306 {
307 bool bHandled = false;
308 switch( rEvt.GetCommand() )
309 {
310 case CommandEventId::ContextMenu:
311 {
312 // Position of click
313 ::Point ptWhere;
314 if (rEvt.IsMouseEvent())
315 {
316 ptWhere = rEvt.GetMousePosPixel();
317 std::unique_ptr<weld::TreeIter> xClickedOn(m_xTreeView->make_iterator());
318 if (!m_xTreeView->get_dest_row_at_pos(ptWhere, xClickedOn.get(), false))
319 break;
320 if (!m_xTreeView->is_selected(*xClickedOn))
321 {
322 m_xTreeView->unselect_all();
323 m_xTreeView->select(*xClickedOn);
324 m_xTreeView->set_cursor(*xClickedOn);
325 }
326 }
327 else
328 {
329 if (m_arrCurrentSelection.empty()) // only happens with context menu via keyboard
330 break;
331
332 std::unique_ptr<weld::TreeIter> xCurrent(m_xTreeView->make_iterator());
333 if (!m_xTreeView->get_cursor(xCurrent.get()))
334 break;
335 ptWhere = m_xTreeView->get_row_area(*xCurrent).Center();
336 }
337
338 // update my selection data
339 CollectSelectionData(SDI_ALL);
340
341 // if there is at least one no-root-entry and the root selected, I deselect root
342 if ( (m_arrCurrentSelection.size() > 1) && m_bRootSelected )
343 {
344 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
345 m_xTreeView->set_cursor(*rIter);
346 m_xTreeView->unselect(*m_xRootEntry);
347 }
348 bool bSingleSelection = (m_arrCurrentSelection.size() == 1);
349
350
351 DBG_ASSERT( (!m_arrCurrentSelection.empty()) || m_bRootSelected, "no entries selected" )do { if (true && (!((!m_arrCurrentSelection.empty()) ||
m_bRootSelected))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "351" ": "), "%s", "no entries selected"); } } while (false
)
;
352 // shouldn't happen, because I would have selected one during call to IsSelected,
353 // if there was none before
354
355
356 // create menu
357 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
358 FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
359 if( pFormShell && pFormModel )
360 {
361 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "svx/ui/formnavimenu.ui"));
362 std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
363 std::unique_ptr<weld::Menu> xSubMenuNew(xBuilder->weld_menu("submenu"));
364
365 // menu 'New' only exists, if only the root or only one form is selected
366 bool bShowNew = bSingleSelection && (m_nFormsSelected || m_bRootSelected);
367 if (!bShowNew)
368 xContextMenu->remove("new");
369
370 // 'New'\'Form' under the same terms
371 bool bShowForm = bSingleSelection && (m_nFormsSelected || m_bRootSelected);
372 if (bShowForm)
373 xSubMenuNew->append("form", SvxResId(RID_STR_FORMreinterpret_cast<char const *>("RID_STR_FORM" "\004" u8"Form"
)
), RID_SVXBMP_FORM"res/sx10593.png");
374
375 // 'New'\'hidden...', if exactly one form is selected
376 bool bShowHidden = bSingleSelection && m_nFormsSelected;
377 if (bShowHidden)
378 xSubMenuNew->append("hidden", SvxResId(RID_STR_HIDDENreinterpret_cast<char const *>("RID_STR_HIDDEN" "\004" u8"Hidden"
)
), RID_SVXBMP_HIDDEN"res/sx18022.png");
379
380 // 'Delete': everything which is not root can be removed
381 if (m_bRootSelected)
382 xContextMenu->remove("delete");
383
384 // 'Cut', 'Copy' and 'Paste'
385 bool bShowCut = !m_bRootSelected && implAllowExchange(DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE);
386 if (!bShowCut)
387 xContextMenu->remove("cut");
388 bool bShowCopy = !m_bRootSelected && implAllowExchange(DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY);
389 if (!bShowCopy)
390 xContextMenu->remove("copy");
391 if (!implAcceptPaste())
392 xContextMenu->remove("paste");
393
394 // TabDialog, if exactly one form
395 bool bShowTabOrder = bSingleSelection && m_nFormsSelected;
396 if (!bShowTabOrder)
397 xContextMenu->remove("taborder");
398
399 bool bShowProps = true;
400 // in XML forms, we don't allow for the properties of a form
401 // #i36484#
402 if (pFormShell->GetImpl()->isEnhancedForm_Lock() && !m_nControlsSelected)
403 bShowProps = false;
404 // if the property browser is already open, we don't allow for the properties, too
405 if (pFormShell->GetImpl()->IsPropBrwOpen_Lock())
406 bShowProps = false;
407
408 // and finally, if there's a mixed selection of forms and controls, disable the entry, too
409 if (bShowProps && !pFormShell->GetImpl()->IsPropBrwOpen_Lock())
410 bShowProps =
411 (m_nControlsSelected && !m_nFormsSelected) || (!m_nControlsSelected && m_nFormsSelected);
412
413 if (!bShowProps)
414 xContextMenu->remove("props");
415
416 // rename, if one element and no root
417 bool bShowRename = bSingleSelection && !m_bRootSelected;
418 if (!bShowRename)
419 xContextMenu->remove("rename");
420
421 if (!m_bRootSelected)
422 {
423 // Readonly-entry is only for root
424 xContextMenu->remove("designmode");
425 // the same for automatic control focus
426 xContextMenu->remove("controlfocus");
427 }
428
429 std::unique_ptr<weld::Menu> xConversionMenu(xBuilder->weld_menu("changemenu"));
430 // ConvertTo-Slots are enabled, if one control is selected
431 // the corresponding slot is disabled
432 if (!m_bRootSelected && !m_nFormsSelected && (m_nControlsSelected == 1))
433 {
434 FmXFormShell::GetConversionMenu_Lock(*xConversionMenu);
435#if OSL_DEBUG_LEVEL1 > 0
436 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
437 FmControlData* pCurrent = reinterpret_cast<FmControlData*>(m_xTreeView->get_id(*rIter).toInt64());
438 OSL_ENSURE( pFormShell->GetImpl()->isSolelySelected_Lock( pCurrent->GetFormComponent() ),do { if (true && (!(pFormShell->GetImpl()->isSolelySelected_Lock
( pCurrent->GetFormComponent() )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "439" ": "), "%s", "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!"
); } } while (false)
439 "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!" )do { if (true && (!(pFormShell->GetImpl()->isSolelySelected_Lock
( pCurrent->GetFormComponent() )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "439" ": "), "%s", "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!"
); } } while (false)
;
440#endif
441
442 pFormShell->GetImpl()->checkControlConversionSlotsForCurrentSelection_Lock(*xConversionMenu);
443 }
444 else
445 xContextMenu->remove("change");
446
447 if (m_bRootSelected)
448 {
449 // set OpenReadOnly
450 xContextMenu->set_active("designmode", pFormModel->GetOpenInDesignMode());
451 xContextMenu->set_active("controlfocus", pFormModel->GetAutoControlFocus());
452 }
453
454 OString sIdent = xContextMenu->popup_at_rect(m_xTreeView.get(), tools::Rectangle(ptWhere, ::Size(1, 1)));
455 if (sIdent == "form")
456 {
457 OUString aStr(SvxResId(RID_STR_FORMreinterpret_cast<char const *>("RID_STR_FORM" "\004" u8"Form"
)
));
458 OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERTreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_INSERT"
"\004" u8"Insert in container")
).replaceAll("#", aStr);
459
460 pFormModel->BegUndo(aUndoStr);
461 // slot was only available, if there is only one selected entry,
462 // which is a root or a form
463 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
464 NewForm(*rIter);
465 pFormModel->EndUndo();
466 }
467 else if (sIdent == "hidden")
468 {
469 OUString aStr(SvxResId(RID_STR_CONTROLreinterpret_cast<char const *>("RID_STR_CONTROL" "\004"
u8"Control")
));
470 OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERTreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_INSERT"
"\004" u8"Insert in container")
).replaceAll("#", aStr);
471
472 pFormModel->BegUndo(aUndoStr);
473 // slot was valid for (exactly) one selected form
474 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
475 NewControl(FM_COMPONENT_HIDDEN"stardiv.one.form.component.Hidden", *rIter, true);
476 pFormModel->EndUndo();
477 }
478 else if (sIdent == "cut")
479 doCut();
480 else if (sIdent == "copy")
481 doCopy();
482 else if (sIdent == "paste")
483 doPaste();
484 else if (sIdent == "delete")
485 DeleteSelection();
486 else if (sIdent == "taborder")
487 {
488 // this slot was effective for exactly one selected form
489 const std::unique_ptr<weld::TreeIter>& rSelectedForm = *m_arrCurrentSelection.begin();
490 DBG_ASSERT( IsFormEntry(*rSelectedForm), "NavigatorTree::Command: This entry must be a FormEntry." )do { if (true && (!(IsFormEntry(*rSelectedForm)))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "490" ": "), "%s", "NavigatorTree::Command: This entry must be a FormEntry."
); } } while (false)
;
491
492 FmFormData* pFormData = reinterpret_cast<FmFormData*>(m_xTreeView->get_id(*rSelectedForm).toInt64());
493 const Reference< XForm >& xForm( pFormData->GetFormIface());
494
495 Reference< XTabControllerModel > xTabController(xForm, UNO_QUERY);
496 if( !xTabController.is() )
497 break;
498 GetNavModel()->GetFormShell()->GetImpl()->ExecuteTabOrderDialog_Lock(xTabController);
499 }
500 else if (sIdent == "props")
501 ShowSelectionProperties(true);
502 else if (sIdent == "rename")
503 {
504 // only allowed for one no-root-entry
505 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
506 m_xTreeView->start_editing(*rIter);
507 m_bEditing = true;
508 }
509 else if (sIdent == "designmode")
510 {
511 pFormModel->SetOpenInDesignMode( !pFormModel->GetOpenInDesignMode() );
512 pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_OPEN_READONLY( 10000 + 709 ));
513 }
514 else if (sIdent == "controlfocus")
515 {
516 pFormModel->SetAutoControlFocus( !pFormModel->GetAutoControlFocus() );
517 pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS( 10000 + 763 ));
518 }
519 else if (FmXFormShell::isControlConversionSlot(sIdent))
520 {
521 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
522 FmControlData* pCurrent = reinterpret_cast<FmControlData*>(m_xTreeView->get_id(*rIter).toInt64());
523 if (pFormShell->GetImpl()->executeControlConversionSlot_Lock(pCurrent->GetFormComponent(), sIdent))
524 ShowSelectionProperties();
525 }
526 }
527 bHandled = true;
528 }
529 break;
530 default: break;
531 }
532
533 return bHandled;
534 }
535
536 std::unique_ptr<weld::TreeIter> NavigatorTree::FindEntry(FmEntryData* pEntryData)
537 {
538 std::unique_ptr<weld::TreeIter> xRet;
539 if(!pEntryData)
540 return xRet;
541
542 m_xTreeView->all_foreach([this, pEntryData, &xRet](weld::TreeIter& rEntry){
543 FmEntryData* pCurEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rEntry).toInt64());
544 if (pCurEntryData && pCurEntryData->IsEqualWithoutChildren(pEntryData))
545 {
546 xRet = m_xTreeView->make_iterator(&rEntry);
547 return true;
548 }
549 return false;
550 });
551
552 return xRet;
553 }
554
555 void NavigatorTree::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
556 {
557 if( dynamic_cast<const FmNavRemovedHint*>(&rHint) )
558 {
559 const FmNavRemovedHint* pRemovedHint = static_cast<const FmNavRemovedHint*>(&rHint);
560 FmEntryData* pEntryData = pRemovedHint->GetEntryData();
561 Remove( pEntryData );
562 }
563
564 else if( dynamic_cast<const FmNavInsertedHint*>(&rHint) )
565 {
566 const FmNavInsertedHint* pInsertedHint = static_cast<const FmNavInsertedHint*>(&rHint);
567 FmEntryData* pEntryData = pInsertedHint->GetEntryData();
568 sal_uInt32 nRelPos = pInsertedHint->GetRelPos();
569 Insert( pEntryData, nRelPos );
570 }
571
572 else if( dynamic_cast<const FmNavModelReplacedHint*>(&rHint) )
573 {
574 FmEntryData* pData = static_cast<const FmNavModelReplacedHint*>(&rHint)->GetEntryData();
575 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pData);
576 if (xEntry)
577 {
578 // reset image
579 m_xTreeView->set_image(*xEntry, pData->GetNormalImage());
580 }
581 }
582
583 else if( dynamic_cast<const FmNavNameChangedHint*>(&rHint) )
584 {
585 const FmNavNameChangedHint* pNameChangedHint = static_cast<const FmNavNameChangedHint*>(&rHint);
586 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pNameChangedHint->GetEntryData());
587 m_xTreeView->set_text(*xEntry, pNameChangedHint->GetNewName());
588 }
589
590 else if( dynamic_cast<const FmNavClearedHint*>(&rHint) )
591 {
592 m_aCutEntries.clear();
593 if (m_aControlExchange.isDataExchangeActive())
594 m_aControlExchange.clear();
595 m_xTreeView->clear();
596
597 // default-entry "Forms"
598 OUString sText(SvxResId(RID_STR_FORMSreinterpret_cast<char const *>("RID_STR_FORMS" "\004" u8"Forms"
)
));
599 m_xRootEntry = m_xTreeView->make_iterator();
600 m_xTreeView->insert(nullptr, -1, &sText, nullptr, nullptr, nullptr,
601 false, m_xRootEntry.get());
602 m_xTreeView->set_image(*m_xRootEntry, RID_SVXBMP_FORMS"res/sx18013.png");
603 m_xTreeView->set_sensitive(*m_xRootEntry, true);
604 }
605 else if (dynamic_cast<const FmNavRequestSelectHint*>(&rHint))
606 {
607 FmNavRequestSelectHint* pershHint = const_cast<FmNavRequestSelectHint*>(static_cast<const FmNavRequestSelectHint*>(&rHint));
608 FmEntryDataArray& arredToSelect = pershHint->GetItems();
609 SynchronizeSelection(arredToSelect);
610
611 if (pershHint->IsMixedSelection())
612 // in this case I deselect all, although the view had a mixed selection
613 // during next selection, I must adapt the navigator to the view
614 m_bPrevSelectionMixed = true;
615 }
616 }
617
618 std::unique_ptr<weld::TreeIter> NavigatorTree::Insert(FmEntryData* pEntryData, int nRelPos)
619 {
620 // insert current entry
621 std::unique_ptr<weld::TreeIter> xParentEntry = FindEntry( pEntryData->GetParent() );
622 std::unique_ptr<weld::TreeIter> xNewEntry(m_xTreeView->make_iterator());
623 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntryData)));
624
625 if(!xParentEntry)
626 {
627 m_xTreeView->insert(m_xRootEntry.get(), nRelPos, &pEntryData->GetText(), &sId,
628 nullptr, nullptr, false, xNewEntry.get());
629 }
630 else
631 {
632 m_xTreeView->insert(xParentEntry.get(), nRelPos, &pEntryData->GetText(), &sId,
633 nullptr, nullptr, false, xNewEntry.get());
634 }
635
636 m_xTreeView->set_image(*xNewEntry, pEntryData->GetNormalImage());
637 m_xTreeView->set_sensitive(*xNewEntry, true);
638
639 // If root-entry, expand root
640 if (!xParentEntry)
641 m_xTreeView->expand_row(*m_xRootEntry);
642
643 // insert children
644 FmEntryDataList* pChildList = pEntryData->GetChildList();
645 size_t nChildCount = pChildList->size();
646 for( size_t i = 0; i < nChildCount; i++ )
647 {
648 FmEntryData* pChildData = pChildList->at( i );
649 Insert(pChildData, -1);
650 }
651
652 return xNewEntry;
653 }
654
655 void NavigatorTree::Remove( FmEntryData* pEntryData )
656 {
657 if( !pEntryData )
658 return;
659
660 // entry for the data
661 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pEntryData);
662 if (!xEntry)
663 return;
664
665 // delete entry from TreeListBox
666 // I'm not allowed, to treat the selection, which I trigger:
667 // select changes the MarkList of the view, if somebody else does this at the same time
668 // and removes a selection, we get a problem
669 // e.g. Group controls with open navigator
670 LockSelectionHandling();
671
672 // little problem: I remember the selected data, but if somebody deletes one of these entries,
673 // I get inconsistent... this would be bad
674 m_xTreeView->unselect(*xEntry);
675
676 // selection can be modified during deletion,
677 // but because I disabled SelectionHandling, I have to do it later
678 auto nExpectedSelectionCount = m_xTreeView->count_selected_rows();
679
680 ModelHasRemoved(xEntry.get());
681 m_xTreeView->remove(*xEntry);
682
683 if (nExpectedSelectionCount != m_xTreeView->count_selected_rows())
684 SynchronizeSelection();
685
686 // by default I treat the selection of course
687 UnlockSelectionHandling();
688 }
689
690 bool NavigatorTree::IsFormEntry(const weld::TreeIter& rEntry)
691 {
692 FmEntryData* pEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rEntry).toInt64());
693 return !pEntryData || dynamic_cast<const FmFormData*>( pEntryData) != nullptr;
694 }
695
696 bool NavigatorTree::IsFormComponentEntry(const weld::TreeIter& rEntry)
697 {
698 FmEntryData* pEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rEntry).toInt64());
699 return dynamic_cast<const FmControlData*>( pEntryData) != nullptr;
700 }
701
702 bool NavigatorTree::implAcceptPaste( )
703 {
704 auto nSelectedEntries = m_xTreeView->count_selected_rows();
705 if (nSelectedEntries != 1)
706 // no selected entry, or at least two selected entries
707 return false;
708
709 // get the clipboard
710 TransferableDataHelper aClipboardContent(TransferableDataHelper::CreateFromClipboard(GetSystemClipboard()));
711
712 sal_Int8 nAction = m_aControlExchange.isClipboardOwner() && doingKeyboardCut( ) ? DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE : DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY;
713 std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
714 if (!m_xTreeView->get_selected(xSelected.get()))
715 xSelected.reset();
716 return nAction == implAcceptDataTransfer(aClipboardContent.GetDataFlavorExVector(), nAction, xSelected.get(), false);
717 }
718
719 sal_Int8 NavigatorTree::implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD )
720 {
721 // no target -> no drop
722 if (!_pTargetEntry)
723 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
724
725 // format check
726 bool bHasDefControlFormat = OControlExchange::hasFieldExchangeFormat( _rFlavors );
727 bool bHasControlPathFormat = OControlExchange::hasControlPathFormat( _rFlavors );
728 bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( _rFlavors );
729 if (!bHasDefControlFormat && !bHasControlPathFormat && !bHasHiddenControlsFormat)
730 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
731
732 bool bSelfSource = _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner();
733
734 if ( bHasHiddenControlsFormat )
735 { // bHasHiddenControlsFormat means that only hidden controls are part of the data
736
737 // hidden controls can be copied to a form only
738 if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0 || !IsFormEntry(*_pTargetEntry))
739 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
740
741 return bSelfSource ? ( DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE & _nAction ) : DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY;
742 }
743
744 if ( !bSelfSource )
745 {
746 // DnD or CnP crossing navigator boundaries
747 // The main problem here is that the current API does not allow us to sneak into the content which
748 // is to be inserted. So we have to allow it for the moment, but maybe reject later on (in the real drop).
749
750 // TODO: this smart behaviour later on ... at the moment, we disallow data transfer crossing navigator
751 // boundaries.
752
753 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
754 }
755
756 DBG_ASSERT( _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner(),do { if (true && (!(_bDnD ? m_aControlExchange.isDragSource
() : m_aControlExchange.isClipboardOwner()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "757" ": "), "%s", "NavigatorTree::implAcceptDataTransfer: here only with source=dest!"
); } } while (false)
757 "NavigatorTree::implAcceptDataTransfer: here only with source=dest!" )do { if (true && (!(_bDnD ? m_aControlExchange.isDragSource
() : m_aControlExchange.isClipboardOwner()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "757" ": "), "%s", "NavigatorTree::implAcceptDataTransfer: here only with source=dest!"
); } } while (false)
;
758 // somebody changed the logic of this method ...
759
760 // from here on, I can work with m_aControlExchange instead of _rData!
761
762 bool bForeignCollection = m_aControlExchange->getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get();
763 if ( bForeignCollection )
764 {
765 // crossing shell/page boundaries, we can exchange hidden controls only
766 // But if we survived the checks above, we do not have hidden controls.
767 // -> no data transfer
768 DBG_ASSERT( !bHasHiddenControlsFormat, "NavigatorTree::implAcceptDataTransfer: still hidden controls format!" )do { if (true && (!(!bHasHiddenControlsFormat))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "768" ": "), "%s", "NavigatorTree::implAcceptDataTransfer: still hidden controls format!"
); } } while (false)
;
769 // somebody changed the logic of this method ...
770
771 return DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY;
772 }
773
774 if (DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE != _nAction) // 'normal' controls within a shell are moved only (never copied)
775 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
776
777 if ( m_bDragDataDirty || !bHasDefControlFormat )
778 {
779 if (!bHasControlPathFormat)
780 // I am in the shell/page, which has the controls, but I have no format,
781 // which survived the shell change (SVX_FM_CONTROLS_AS_PATH)
782 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
783
784 // I must recreate the list of the ExchangeObjects, because the shell was changed during dragging
785 // (there are SvLBoxEntries in it, and we lost them during change)
786 m_aControlExchange->buildListFromPath(m_xTreeView.get(), m_xRootEntry.get());
787 m_bDragDataDirty = false;
788 }
789
790 // List of dropped entries from DragServer
791 const ListBoxEntrySet& rDropped = m_aControlExchange->selected();
792 DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implAcceptDataTransfer: no entries !")do { if (true && (!(!rDropped.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "792" ": "), "%s", "NavigatorTree::implAcceptDataTransfer: no entries !"
); } } while (false)
;
793
794 bool bDropTargetIsComponent = IsFormComponentEntry( *_pTargetEntry );
795
796 // conditions to disallow the drop
797 // 0) the root entry is part of the list (can't DnD the root!)
798 // 1) one of the dragged entries is to be dropped onto its own parent
799 // 2) - " - is to be dropped onto itself
800 // 3) - " - is a Form and to be dropped onto one of its descendants
801 // 4) one of the entries is a control and to be dropped onto the root
802 // 5) a control or form will be dropped onto a control which is _not_ a sibling (dropping onto a sibling
803 // means moving the control)
804
805 // collect the ancestors of the drop target (speeds up 3)
806 SvLBoxEntrySortedArray arrDropAncestors;
807 std::unique_ptr<weld::TreeIter> xLoop(m_xTreeView->make_iterator(_pTargetEntry));
808 do
809 {
810 arrDropAncestors.emplace(m_xTreeView->make_iterator(xLoop.get()));
811 }
812 while (m_xTreeView->iter_parent(*xLoop));
813
814 for (const auto& rCurrent : rDropped)
815 {
816 // test for 0)
817 if (m_xTreeView->iter_compare(*rCurrent, *m_xRootEntry) == 0)
818 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
819
820 std::unique_ptr<weld::TreeIter> xCurrentParent(m_xTreeView->make_iterator(rCurrent.get()));
821 m_xTreeView->iter_parent(*xCurrentParent);
822
823 // test for 1)
824 if (m_xTreeView->iter_compare(*_pTargetEntry, *xCurrentParent) == 0)
825 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
826
827 // test for 2)
828 if (m_xTreeView->iter_compare(*rCurrent, *_pTargetEntry) == 0)
829 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
830
831 // test for 5)
832 if (bDropTargetIsComponent)
833 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
834
835 // test for 3)
836 if (IsFormEntry(*rCurrent))
837 {
838 auto aIter = std::find_if(arrDropAncestors.begin(), arrDropAncestors.end(),
839 [this, &rCurrent](const auto& rElem) {
840 return m_xTreeView->iter_compare(*rElem, *rCurrent) == 0;
841 });
842
843 if ( aIter != arrDropAncestors.end() )
844 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
845 }
846 else if (IsFormComponentEntry(*rCurrent))
847 {
848 // test for 4)
849 if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0)
850 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
851 }
852 }
853 return DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE;
854 }
855
856 sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& rEvt )
857 {
858 ::Point aDropPos = rEvt.maPosPixel;
859 std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator());
860 // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it
861 if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), false))
862 xDropTarget.reset();
863 return implAcceptDataTransfer(m_aDropTargetHelper.GetDataFlavorExVector(), rEvt.mnAction, xDropTarget.get(), true);
864 }
865
866 sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const ::Point& _rDropPos, bool _bDnD )
867 {
868 std::unique_ptr<weld::TreeIter> xDrop(m_xTreeView->make_iterator());
869 // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it
870 if (!m_xTreeView->get_dest_row_at_pos(_rDropPos, xDrop.get(), false))
871 xDrop.reset();
872 return implExecuteDataTransfer( _rData, _nAction, xDrop.get(), _bDnD );
873 }
874
875 sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD )
876 {
877 const DataFlavorExVector& rDataFlavors = _rData.GetDataFlavorExVector();
878
879 if ( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE == implAcceptDataTransfer( rDataFlavors, _nAction, _pTargetEntry, _bDnD ) )
880 // under some platforms, it may happen that ExecuteDrop is called though AcceptDrop returned DND_ACTION_NONE
881 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
882
883 if (!_pTargetEntry)
884 // no target -> no drop
885 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
886
887 // format checks
888#ifdef DBG_UTIL
889 bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( rDataFlavors );
890 bool bForeignCollection = _rData.getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get();
891 DBG_ASSERT(!bForeignCollection || bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: invalid format (AcceptDrop shouldn't have let this pass) !")do { if (true && (!(!bForeignCollection || bHasHiddenControlsFormat
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "891" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid format (AcceptDrop shouldn't have let this pass) !"
); } } while (false)
;
892 DBG_ASSERT(bForeignCollection || !m_bDragDataDirty, "NavigatorTree::implExecuteDataTransfer: invalid state (shell changed since last exchange resync) !")do { if (true && (!(bForeignCollection || !m_bDragDataDirty
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "892" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid state (shell changed since last exchange resync) !"
); } } while (false)
;
893 // this should be done in AcceptDrop: the list of controls is created in _rData
894 // and m_bDragDataDirty is reset
895#endif
896
897 if ( DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY == _nAction )
898 { // bHasHiddenControlsFormat means that only hidden controls are part of the data
899#ifdef DBG_UTIL
900 DBG_ASSERT( bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: copy allowed for hidden controls only!" )do { if (true && (!(bHasHiddenControlsFormat))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "900" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: copy allowed for hidden controls only!"
); } } while (false)
;
901#endif
902 DBG_ASSERT( _pTargetEntry && m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) != 0 && IsFormEntry( *_pTargetEntry ),do { if (true && (!(_pTargetEntry && m_xTreeView
->iter_compare(*_pTargetEntry, *m_xRootEntry) != 0 &&
IsFormEntry( *_pTargetEntry )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "903" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: should not be here!"
); } } while (false)
903 "NavigatorTree::implExecuteDataTransfer: should not be here!" )do { if (true && (!(_pTargetEntry && m_xTreeView
->iter_compare(*_pTargetEntry, *m_xRootEntry) != 0 &&
IsFormEntry( *_pTargetEntry )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "903" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: should not be here!"
); } } while (false)
;
904 // implAcceptDataTransfer should have caught both cases
905
906#ifdef DBG_UTIL
907 DBG_ASSERT(bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: only copying of hidden controls is supported !")do { if (true && (!(bHasHiddenControlsFormat))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "907" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: only copying of hidden controls is supported !"
); } } while (false)
;
908 // should be caught by AcceptDrop
909#endif
910
911 // because i want to select all targets (and only them)
912 m_xTreeView->unselect_all();
913
914 const Sequence< Reference< XInterface > >& aControls = _rData.hiddenControls();
915 sal_Int32 nCount = aControls.getLength();
916 const Reference< XInterface >* pControls = aControls.getConstArray();
917
918 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
919 FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
920
921 // within undo
922 if (pFormModel)
923 {
924 OUString aStr(SvxResId(RID_STR_CONTROLreinterpret_cast<char const *>("RID_STR_CONTROL" "\004"
u8"Control")
));
925 OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERTreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_INSERT"
"\004" u8"Insert in container")
).replaceAll("#", aStr);
926 pFormModel->BegUndo(aUndoStr);
927 }
928
929 // copy controls
930 for (sal_Int32 i=0; i<nCount; ++i)
931 {
932 // create new control
933 FmControlData* pNewControlData = NewControl( FM_COMPONENT_HIDDEN"stardiv.one.form.component.Hidden", *_pTargetEntry, false);
934 Reference< XPropertySet > xNewPropSet( pNewControlData->GetPropertySet() );
935
936 // copy properties form old control to new one
937 Reference< XPropertySet > xCurrent(pControls[i], UNO_QUERY);
938#if (OSL_DEBUG_LEVEL1 > 0)
939 // check whether it is a hidden control
940 sal_Int16 nClassId = ::comphelper::getINT16(xCurrent->getPropertyValue(FM_PROP_CLASSID"ClassId"));
941 OSL_ENSURE(nClassId == FormComponentType::HIDDENCONTROL, "NavigatorTree::implExecuteDataTransfer: invalid control in drop list !")do { if (true && (!(nClassId == FormComponentType::HIDDENCONTROL
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "941" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid control in drop list !"
); } } while (false)
;
942 // if SVX_FM_HIDDEN_CONTROLS-format exists, the sequence
943 // should only contain hidden controls
944#endif // (OSL_DEBUG_LEVEL > 0)
945 Reference< XPropertySetInfo > xPropInfo( xCurrent->getPropertySetInfo());
946 const Sequence< Property> seqAllCurrentProps = xPropInfo->getProperties();
947 for (Property const & currentProp : seqAllCurrentProps)
948 {
949 if (((currentProp.Attributes & PropertyAttribute::READONLY) == 0) && (currentProp.Name != FM_PROP_NAME"Name"))
950 { // (read-only attribs aren't set, ditto name,
951 // NewControl defined it uniquely
952 xNewPropSet->setPropertyValue(currentProp.Name, xCurrent->getPropertyValue(currentProp.Name));
953 }
954 }
955
956 std::unique_ptr<weld::TreeIter> xToSelect = FindEntry(pNewControlData);
957 m_xTreeView->select(*xToSelect);
958 if (i == 0)
959 m_xTreeView->set_cursor(*xToSelect);
960 }
961
962 if (pFormModel)
963 pFormModel->EndUndo();
964
965 return _nAction;
966 }
967
968 if ( !OControlExchange::hasFieldExchangeFormat( _rData.GetDataFlavorExVector() ) )
969 {
970 // can't do anything without the internal format here ... usually happens when doing DnD or CnP
971 // over navigator boundaries
972 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
973 }
974
975 // some data for the target
976 bool bDropTargetIsForm = IsFormEntry(*_pTargetEntry);
977 FmFormData* pTargetData = bDropTargetIsForm ? reinterpret_cast<FmFormData*>(m_xTreeView->get_id(*_pTargetEntry).toInt64()) : nullptr;
978
979 DBG_ASSERT( DND_ACTION_COPY != _nAction, "NavigatorTree::implExecuteDataTransfer: somebody changed the logics!" )do { if (true && (!(css::datatransfer::dnd::DNDConstants
::ACTION_COPY != _nAction))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "979" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: somebody changed the logics!"
); } } while (false)
;
980
981 // list of dragged entries
982 const ListBoxEntrySet& rDropped = _rData.selected();
983 DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implExecuteDataTransfer: no entries!")do { if (true && (!(!rDropped.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "983" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: no entries!"
); } } while (false)
;
984
985 // make a copy because rDropped is updated on deleting an entry which we do in the processing loop
986 ListBoxEntrySet aDropped;
987 for (const auto& rEntry : rDropped)
988 aDropped.emplace(m_xTreeView->make_iterator(rEntry.get()));
989
990 // shell and model
991 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
992 FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
993 if (!pFormModel)
994 return DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
995
996 // for Undo
997 const bool bUndo = pFormModel->IsUndoEnabled();
998
999 if( bUndo )
1000 {
1001 OUString strUndoDescription(SvxResId(RID_STR_UNDO_CONTAINER_REPLACEreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_REPLACE"
"\004" u8"Replace a container element")
));
1002 pFormModel->BegUndo(strUndoDescription);
1003 }
1004
1005 // remove selection before adding an entry, so the mark doesn't flicker
1006 // -> lock action of selection
1007 LockSelectionHandling();
1008
1009 // go through all dropped entries
1010 for ( ListBoxEntrySet::const_iterator dropped = aDropped.begin();
1011 dropped != aDropped.end();
1012 ++dropped
1013 )
1014 {
1015 bool bFirstEntry = aDropped.begin() == dropped;
1016
1017 // some data of the current element
1018 const auto& rCurrent = *dropped;
1019 DBG_ASSERT(rCurrent, "NavigatorTree::implExecuteDataTransfer: invalid entry")do { if (true && (!(rCurrent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1019" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid entry"
); } } while (false)
;
1020 DBG_ASSERT(m_xTreeView->get_iter_depth(*rCurrent) != 0, "NavigatorTree::implExecuteDataTransfer: invalid entry")do { if (true && (!(m_xTreeView->get_iter_depth(*rCurrent
) != 0))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN),
("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1020" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid entry"
); } } while (false)
;
1021 // don't drag root
1022
1023 FmEntryData* pCurrentUserData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rCurrent).toInt64());
1024
1025 Reference< XChild > xCurrentChild = pCurrentUserData->GetChildIFace();
1026 Reference< XIndexContainer > xContainer(xCurrentChild->getParent(), UNO_QUERY);
1027
1028 FmFormData* pCurrentParentUserData = static_cast<FmFormData*>(pCurrentUserData->GetParent());
1029 DBG_ASSERT(pCurrentParentUserData == nullptr || dynamic_cast<const FmFormData*>(pCurrentUserData->GetParent()) != nullptr, "NavigatorTree::implExecuteDataTransfer: invalid parent")do { if (true && (!(pCurrentParentUserData == nullptr
|| dynamic_cast<const FmFormData*>(pCurrentUserData->
GetParent()) != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1029" ": "), "%s", "NavigatorTree::implExecuteDataTransfer: invalid parent"
); } } while (false)
;
1030
1031 // remove from parent
1032 if (pCurrentParentUserData)
1033 pCurrentParentUserData->GetChildList()->removeNoDelete( pCurrentUserData );
1034 else
1035 GetNavModel()->GetRootList()->removeNoDelete( pCurrentUserData );
1036
1037 // remove from container
1038 sal_Int32 nIndex = getElementPos(xContainer, xCurrentChild);
1039 GetNavModel()->m_pPropChangeList->Lock();
1040 // UndoAction for removal
1041 if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo())
1042 {
1043 pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*pFormModel, FmUndoContainerAction::Removed,
1044 xContainer, xCurrentChild, nIndex));
1045 }
1046 else if( !GetNavModel()->m_pPropChangeList->CanUndo() )
1047 {
1048 FmUndoContainerAction::DisposeElement( xCurrentChild );
1049 }
1050
1051 // copy events
1052 Reference< XEventAttacherManager > xManager(xContainer, UNO_QUERY);
1053 Sequence< ScriptEventDescriptor > aEvts;
1054
1055 if (xManager.is() && nIndex >= 0)
1056 aEvts = xManager->getScriptEvents(nIndex);
1057 xContainer->removeByIndex(nIndex);
1058
1059 // remove selection
1060 m_xTreeView->unselect(*rCurrent);
1061 // and delete it
1062 Remove(pCurrentUserData);
1063
1064 // position in DropParents, where to insert dropped entries
1065 if (pTargetData)
1066 xContainer.set(pTargetData->GetElement(), UNO_QUERY);
1067 else
1068 xContainer = GetNavModel()->GetForms();
1069
1070 // always insert at the end
1071 nIndex = xContainer->getCount();
1072
1073 // UndoAction for insertion
1074 if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo())
1075 pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*pFormModel, FmUndoContainerAction::Inserted,
1076 xContainer, xCurrentChild, nIndex));
1077
1078 // insert in new container
1079 if (pTargetData)
1080 {
1081 // insert in a form needs a FormComponent
1082 xContainer->insertByIndex( nIndex,
1083 makeAny( Reference< XFormComponent >( xCurrentChild, UNO_QUERY ) ) );
1084 }
1085 else
1086 {
1087 xContainer->insertByIndex( nIndex,
1088 makeAny( Reference< XForm >( xCurrentChild, UNO_QUERY ) ) );
1089 }
1090
1091 if (aEvts.hasElements())
1092 {
1093 xManager.set(xContainer, UNO_QUERY);
1094 if (xManager.is())
1095 xManager->registerScriptEvents(nIndex, aEvts);
1096 }
1097
1098 GetNavModel()->m_pPropChangeList->UnLock();
1099
1100 // give an entry the new parent
1101 pCurrentUserData->SetParent(pTargetData);
1102
1103 // give parent the new child
1104 if (pTargetData)
1105 pTargetData->GetChildList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex );
1106 else
1107 GetNavModel()->GetRootList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex );
1108
1109 // announce to myself and reselect
1110 std::unique_ptr<weld::TreeIter> xNew = Insert( pCurrentUserData, nIndex );
1111 if (bFirstEntry && xNew)
1112 {
1113 if (m_xTreeView->iter_parent(*xNew))
1114 m_xTreeView->expand_row(*xNew);
1115 }
1116 }
1117
1118 UnlockSelectionHandling();
1119
1120 if( bUndo )
1121 pFormModel->EndUndo();
1122
1123 // During the move, the markings of the underlying view did not change (because the view is not affected by the logical
1124 // hierarchy of the form/control models. But my selection changed - which means I have to adjust it according to the
1125 // view marks, again.
1126 SynchronizeSelection();
1127
1128 // in addition, with the move of controls such things as "the current form" may have changed - force the shell
1129 // to update itself accordingly
1130 if( pFormShell && pFormShell->GetImpl() && pFormShell->GetFormView() )
1131 pFormShell->GetImpl()->DetermineSelection_Lock( pFormShell->GetFormView()->GetMarkedObjectList() );
1132
1133 if ( m_aControlExchange.isClipboardOwner() && ( DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE == _nAction ) )
1134 m_aControlExchange->clear();
1135
1136 return _nAction;
1137 }
1138
1139 sal_Int8 NavigatorTree::ExecuteDrop( const ExecuteDropEvent& rEvt )
1140 {
1141 sal_Int8 nResult( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE );
1142 if ( m_aControlExchange.isDragSource() )
1143 nResult = implExecuteDataTransfer( *m_aControlExchange, rEvt.mnAction, rEvt.maPosPixel, true );
1144 else
1145 {
1146 OControlTransferData aDroppedData( rEvt.maDropEvent.Transferable );
1147 nResult = implExecuteDataTransfer( aDroppedData, rEvt.mnAction, rEvt.maPosPixel, true );
1148 }
1149 return nResult;
1150 }
1151
1152 void NavigatorTree::doPaste()
1153 {
1154 std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
1155 if (!m_xTreeView->get_selected(xSelected.get()))
1156 xSelected.reset();
1157
1158 try
1159 {
1160 if ( m_aControlExchange.isClipboardOwner() )
1161 {
1162 implExecuteDataTransfer( *m_aControlExchange, doingKeyboardCut( ) ? DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE : DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY, xSelected.get(), false );
1163 }
1164 else
1165 {
1166 // the clipboard content
1167 Reference< XClipboard > xClipboard( GetSystemClipboard() );
1168 Reference< XTransferable > xTransferable;
1169 if ( xClipboard.is() )
1170 xTransferable = xClipboard->getContents();
1171
1172 OControlTransferData aClipboardContent( xTransferable );
1173 implExecuteDataTransfer( aClipboardContent, DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY, xSelected.get(), false );
1174 }
1175 }
1176 catch( const Exception& )
1177 {
1178 TOOLS_WARN_EXCEPTION( "svx", "NavigatorTree::doPaste" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::doPaste" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1178" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::doPaste" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"NavigatorTree::doPaste" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1178" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::doPaste" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1178" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::doPaste" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"NavigatorTree::doPaste" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("svx"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1178" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1179 }
1180 }
1181
1182 void NavigatorTree::doCopy()
1183 {
1184 if ( implPrepareExchange( DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY ) )
1185 {
1186 m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction )::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubOnClipboardAction)
);
1187 m_aControlExchange.copyToClipboard( );
1188 }
1189 }
1190
1191 void NavigatorTree::ModelHasRemoved(const weld::TreeIter* pTypedEntry)
1192 {
1193 if (doingKeyboardCut())
1194 {
1195 auto aIter = std::find_if(m_aCutEntries.begin(), m_aCutEntries.end(),
1196 [this, pTypedEntry](const auto& rElem) {
1197 return m_xTreeView->iter_compare(*rElem, *pTypedEntry) == 0;
1198 });
1199 if (aIter != m_aCutEntries.end())
1200 m_aCutEntries.erase(aIter);
1201 }
1202
1203 if (m_aControlExchange.isDataExchangeActive())
1204 {
1205 if (0 == m_aControlExchange->onEntryRemoved(m_xTreeView.get(), pTypedEntry))
1206 {
1207 // last of the entries which we put into the clipboard has been deleted from the tree.
1208 // Give up the clipboard ownership.
1209 m_aControlExchange.clear();
1210 }
1211 }
1212 }
1213
1214 void NavigatorTree::doCut()
1215 {
1216 if ( !implPrepareExchange( DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
1217 return;
1218
1219 m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction )::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubOnClipboardAction)
);
1220 m_aControlExchange.copyToClipboard( );
1221 m_bKeyboardCut = true;
1222
1223 // mark all the entries we just "cut" into the clipboard as "nearly moved"
1224 for (const auto& rEntry : m_arrCurrentSelection )
1225 {
1226 if (!rEntry)
1227 continue;
1228 m_aCutEntries.emplace(m_xTreeView->make_iterator(rEntry.get()));
1229 m_xTreeView->set_sensitive(*rEntry, false);
1230 }
1231 }
1232
1233 IMPL_LINK(NavigatorTree, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)bool NavigatorTree::LinkStubKeyInputHdl(void * instance, const
::KeyEvent& data) { return static_cast<NavigatorTree *
>(instance)->KeyInputHdl(data); } bool NavigatorTree::KeyInputHdl
(const ::KeyEvent& rKEvt)
1
Calling 'NavigatorTree::KeyInputHdl'
1234 {
1235 const vcl::KeyCode& rCode = rKEvt.GetKeyCode();
1236
1237 // delete?
1238 if (rCode.GetCode() == KEY_DELETE && !rCode.GetModifier())
2
Assuming the condition is true
3
Assuming the condition is true
4
Taking true branch
1239 {
1240 DeleteSelection();
5
Calling 'NavigatorTree::DeleteSelection'
1241 return true;
1242 }
1243
1244 // copy'n'paste?
1245 switch ( rCode.GetFunction() )
1246 {
1247 case KeyFuncType::CUT:
1248 doCut();
1249 break;
1250
1251 case KeyFuncType::PASTE:
1252 if ( implAcceptPaste() )
1253 doPaste();
1254 break;
1255
1256 case KeyFuncType::COPY:
1257 doCopy();
1258 break;
1259
1260 default:
1261 break;
1262 }
1263
1264 return false;
1265 }
1266
1267 IMPL_LINK(NavigatorTree, EditingEntryHdl, const weld::TreeIter&, rIter, bool)bool NavigatorTree::LinkStubEditingEntryHdl(void * instance, const
weld::TreeIter& data) { return static_cast<NavigatorTree
*>(instance)->EditingEntryHdl(data); } bool NavigatorTree
::EditingEntryHdl(const weld::TreeIter& rIter)
1268 {
1269 // root, which isn't allowed to be renamed, has UserData=NULL
1270 m_bEditing = !m_xTreeView->get_id(rIter).isEmpty();
1271 return m_bEditing;
1272 }
1273
1274 void NavigatorTree::NewForm(const weld::TreeIter& rParentEntry)
1275 {
1276 // get ParentFormData
1277 if (!IsFormEntry(rParentEntry))
1278 return;
1279
1280 FmFormData* pParentFormData = reinterpret_cast<FmFormData*>(m_xTreeView->get_id(rParentEntry).toInt64());
1281
1282
1283 // create new form
1284 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1285 Reference< XForm > xNewForm(xContext->getServiceManager()->createInstanceWithContext(FM_SUN_COMPONENT_FORM"com.sun.star.form.component.Form", xContext), UNO_QUERY);
1286 if (!xNewForm.is())
1287 return;
1288
1289 Reference< XPropertySet > xPropertySet(xNewForm, UNO_QUERY);
1290 if (!xPropertySet.is())
1291 return;
1292
1293 FmFormData* pNewFormData = new FmFormData(xNewForm, pParentFormData);
1294
1295
1296 // set name
1297 OUString aName = GenerateName(pNewFormData);
1298 pNewFormData->SetText(aName);
1299
1300 try
1301 {
1302 xPropertySet->setPropertyValue( FM_PROP_NAME"Name", makeAny(aName) );
1303 // a form should always have the command type table as default
1304 xPropertySet->setPropertyValue( FM_PROP_COMMANDTYPE"CommandType", makeAny(sal_Int32(CommandType::TABLE)));
1305 }
1306 catch ( const Exception& )
1307 {
1308 OSL_FAIL("NavigatorTree::NewForm : could not set essential properties!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1308" ": "), "%s", "NavigatorTree::NewForm : could not set essential properties!"
); } } while (false)
;
1309 }
1310
1311
1312 // insert form
1313 GetNavModel()->Insert(pNewFormData, SAL_MAX_UINT32((sal_uInt32) 0xFFFFFFFF), true);
1314
1315
1316 // set new form as active
1317 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1318 if( pFormShell )
1319 {
1320 InterfaceBag aSelection;
1321 aSelection.insert( Reference<XInterface>( xNewForm, UNO_QUERY ) );
1322 pFormShell->GetImpl()->setCurrentSelection_Lock(aSelection);
1323
1324 pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_PROPERTIES( 10000 + 614 ), true, true);
1325 }
1326 GetNavModel()->SetModified();
1327
1328 // switch to EditMode
1329 std::unique_ptr<weld::TreeIter> xNewEntry = FindEntry(pNewFormData);
1330 m_xTreeView->start_editing(*xNewEntry);
1331 m_bEditing = true;
1332 }
1333
1334 FmControlData* NavigatorTree::NewControl(const OUString& rServiceName, const weld::TreeIter& rParentEntry, bool bEditName)
1335 {
1336 // get ParentForm
1337 if (!GetNavModel()->GetFormShell())
1338 return nullptr;
1339 if (!IsFormEntry(rParentEntry))
1340 return nullptr;
1341
1342 FmFormData* pParentFormData = reinterpret_cast<FmFormData*>(m_xTreeView->get_id(rParentEntry).toInt64());
1343 Reference<XForm> xParentForm(pParentFormData->GetFormIface());
1344
1345 // create new component
1346 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1347 Reference<XFormComponent> xNewComponent( xContext->getServiceManager()->createInstanceWithContext(rServiceName, xContext), UNO_QUERY);
1348 if (!xNewComponent.is())
1349 return nullptr;
1350
1351 FmControlData* pNewFormControlData = new FmControlData(xNewComponent, pParentFormData);
1352
1353 // set name
1354 OUString sName = FmFormPageImpl::setUniqueName( xNewComponent, xParentForm );
1355
1356 pNewFormControlData->SetText( sName );
1357
1358 // insert FormComponent
1359 GetNavModel()->Insert(pNewFormControlData, SAL_MAX_UINT32((sal_uInt32) 0xFFFFFFFF), true);
1360 GetNavModel()->SetModified();
1361
1362 if (bEditName)
1363 {
1364 // switch to EditMode
1365 std::unique_ptr<weld::TreeIter> xNewEntry = FindEntry( pNewFormControlData );
1366 m_xTreeView->select(*xNewEntry);
1367
1368 m_xTreeView->start_editing(*xNewEntry);
1369 m_bEditing = true;
1370 }
1371
1372 return pNewFormControlData;
1373 }
1374
1375 OUString NavigatorTree::GenerateName( FmEntryData const * pEntryData )
1376 {
1377 const sal_uInt16 nMaxCount = 99;
1378 OUString aNewName;
1379
1380 // create base name
1381 OUString aBaseName;
1382 if( dynamic_cast<const FmFormData*>( pEntryData) != nullptr )
1383 aBaseName = SvxResId( RID_STR_STDFORMNAMEreinterpret_cast<char const *>("RID_STR_STDFORMNAME" "\004"
u8"Form")
);
1384 else if( dynamic_cast<const FmControlData*>( pEntryData) != nullptr )
1385 aBaseName = SvxResId( RID_STR_CONTROLreinterpret_cast<char const *>("RID_STR_CONTROL" "\004"
u8"Control")
);
1386
1387
1388 // create new name
1389 FmFormData* pFormParentData = static_cast<FmFormData*>(pEntryData->GetParent());
1390
1391 for( sal_Int32 i=0; i<nMaxCount; i++ )
1392 {
1393 aNewName = aBaseName;
1394 if( i>0 )
1395 {
1396 aNewName += " " + OUString::number(i);
1397 }
1398
1399 if( GetNavModel()->FindData(aNewName, pFormParentData,false) == nullptr )
1400 break;
1401 }
1402
1403 return aNewName;
1404 }
1405
1406 IMPL_LINK(NavigatorTree, EditedEntryHdl, const IterString&, rIterString, bool)bool NavigatorTree::LinkStubEditedEntryHdl(void * instance, const
IterString& data) { return static_cast<NavigatorTree *
>(instance)->EditedEntryHdl(data); } bool NavigatorTree
::EditedEntryHdl(const IterString& rIterString)
1407 {
1408 m_bEditing = false;
1409
1410 const weld::TreeIter& rIter = rIterString.first;
1411
1412 FmEntryData* pEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rIter).toInt64());
1413 bool bRes = NavigatorTreeModel::Rename(pEntryData, rIterString.second);
1414 if (!bRes)
1415 {
1416 m_xEditEntry = m_xTreeView->make_iterator(&rIter);
1417 nEditEvent = Application::PostUserEvent(LINK(this, NavigatorTree, OnEdit)::tools::detail::makeLink( ::tools::detail::castTo<NavigatorTree
*>(this), &NavigatorTree::LinkStubOnEdit)
);
1418 }
1419
1420 return bRes;
1421 }
1422
1423 IMPL_LINK_NOARG(NavigatorTree, OnEdit, void*, void)void NavigatorTree::LinkStubOnEdit(void * instance, void* data
) { return static_cast<NavigatorTree *>(instance)->OnEdit
(data); } void NavigatorTree::OnEdit(__attribute__ ((unused))
void*)
1424 {
1425 nEditEvent = nullptr;
1426 m_xTreeView->start_editing(*m_xEditEntry);
1427 m_bEditing = true;
1428 m_xEditEntry.reset();
1429 }
1430
1431 IMPL_LINK_NOARG(NavigatorTree, OnEntrySelDesel, weld::TreeView&, void)void NavigatorTree::LinkStubOnEntrySelDesel(void * instance, weld
::TreeView& data) { return static_cast<NavigatorTree *
>(instance)->OnEntrySelDesel(data); } void NavigatorTree
::OnEntrySelDesel(__attribute__ ((unused)) weld::TreeView&
)
1432 {
1433 m_sdiState = SDI_DIRTY;
1434
1435 if (IsSelectionHandlingLocked())
1436 return;
1437
1438 if (m_aSynchronizeTimer.IsActive())
1439 m_aSynchronizeTimer.Stop();
1440
1441 m_aSynchronizeTimer.SetTimeout(EXPLORER_SYNC_DELAY200);
1442 m_aSynchronizeTimer.Start();
1443 }
1444
1445 IMPL_LINK_NOARG(NavigatorTree, OnSynchronizeTimer, Timer *, void)void NavigatorTree::LinkStubOnSynchronizeTimer(void * instance
, Timer * data) { return static_cast<NavigatorTree *>(instance
)->OnSynchronizeTimer(data); } void NavigatorTree::OnSynchronizeTimer
(__attribute__ ((unused)) Timer *)
1446 {
1447 SynchronizeMarkList();
1448 }
1449
1450 IMPL_LINK_NOARG(NavigatorTree, OnClipboardAction, OLocalExchange&, void)void NavigatorTree::LinkStubOnClipboardAction(void * instance
, OLocalExchange& data) { return static_cast<NavigatorTree
*>(instance)->OnClipboardAction(data); } void NavigatorTree
::OnClipboardAction(__attribute__ ((unused)) OLocalExchange&
)
1451 {
1452 if ( m_aControlExchange.isClipboardOwner() )
1453 return;
1454
1455 if ( !doingKeyboardCut() )
1456 return;
1457
1458 for (const auto& rEntry : m_aCutEntries)
1459 {
1460 if (!rEntry)
1461 continue;
1462 m_xTreeView->set_sensitive(*rEntry, true);
1463 }
1464 ListBoxEntrySet aEmpty;
1465 m_aCutEntries.swap( aEmpty );
1466
1467 m_bKeyboardCut = false;
1468 }
1469
1470 void NavigatorTree::ShowSelectionProperties(bool bForce)
1471 {
1472 // at first i need the FormShell
1473 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1474 if (!pFormShell)
1475 // no shell -> impossible to set curObject -> leave
1476 return;
1477
1478 CollectSelectionData(SDI_ALL);
1479 SAL_WARN_IF(static_cast<size_t>(m_nFormsSelected + m_nControlsSelecteddo { if (true && (static_cast<size_t>(m_nFormsSelected
+ m_nControlsSelected + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection
.size())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svx.form")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1480 + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection.size(),do { if (true && (static_cast<size_t>(m_nFormsSelected
+ m_nControlsSelected + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection
.size())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svx.form")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1481 "svx.form",do { if (true && (static_cast<size_t>(m_nFormsSelected
+ m_nControlsSelected + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection
.size())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svx.form")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1482 "NavigatorTree::ShowSelectionProperties : selection meta data invalid !")do { if (true && (static_cast<size_t>(m_nFormsSelected
+ m_nControlsSelected + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection
.size())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svx.form")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svx.form"
), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1482" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1483
1484
1485 InterfaceBag aSelection;
1486 bool bSetSelectionAsMarkList = false;
1487
1488 if (m_bRootSelected)
1489 ; // no properties for the root, neither for single nor for multi selection
1490 else if ( m_nFormsSelected + m_nControlsSelected == 0 ) // none of the two should be less 0
1491 ; // no selection -> no properties
1492 else if ( m_nFormsSelected * m_nControlsSelected != 0 )
1493 ; // mixed selection -> no properties
1494 else
1495 { // either only forms, or only controls are selected
1496 if (m_arrCurrentSelection.size() == 1)
1497 {
1498 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
1499 if (m_nFormsSelected > 0)
1500 { // exactly one form is selected
1501 FmFormData* pFormData = reinterpret_cast<FmFormData*>(m_xTreeView->get_id(*rIter).toInt64());
1502 aSelection.insert( Reference< XInterface >( pFormData->GetFormIface(), UNO_QUERY ) );
1503 }
1504 else
1505 { // exactly one control is selected (whatever hidden or normal)
1506 FmEntryData* pEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rIter).toInt64());
1507
1508 aSelection.insert( Reference< XInterface >( pEntryData->GetElement(), UNO_QUERY ) );
1509 }
1510 }
1511 else
1512 { // it's a MultiSelection, so we must build a MultiSet
1513 if (m_nFormsSelected > 0)
1514 { // ... only forms
1515 // first of all collect PropertySet-Interfaces of the forms
1516 SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin();
1517 for ( sal_Int32 i = 0; i < m_nFormsSelected; ++i )
1518 {
1519 const std::unique_ptr<weld::TreeIter>& rIter = *it;
1520 FmFormData* pFormData = reinterpret_cast<FmFormData*>(m_xTreeView->get_id(*rIter).toInt64());
1521 aSelection.insert( pFormData->GetPropertySet().get() );
1522 ++it;
1523 }
1524 }
1525 else
1526 { // ... only controls
1527 if (m_nHiddenControls == m_nControlsSelected)
1528 { // a MultiSet for properties of hidden controls
1529 SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin();
1530 for ( sal_Int32 i = 0; i < m_nHiddenControls; ++i )
1531 {
1532 const std::unique_ptr<weld::TreeIter>& rIter = *it;
1533 FmEntryData* pEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rIter).toInt64());
1534 aSelection.insert( pEntryData->GetPropertySet().get() );
1535 ++it;
1536 }
1537 }
1538 else if (m_nHiddenControls == 0)
1539 { // only normal controls
1540 bSetSelectionAsMarkList = true;
1541 }
1542 }
1543 }
1544
1545 }
1546
1547 // and now my form and my SelObject
1548 if ( bSetSelectionAsMarkList )
1549 pFormShell->GetImpl()->setCurrentSelectionFromMark_Lock(pFormShell->GetFormView()->GetMarkedObjectList());
1550 else
1551 pFormShell->GetImpl()->setCurrentSelection_Lock(aSelection);
1552
1553 if (pFormShell->GetImpl()->IsPropBrwOpen_Lock() || bForce)
1554 {
1555 // and now deliver all to the PropertyBrowser
1556 pFormShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER( 10000 + 703 ), SfxCallMode::ASYNCHRON );
1557 }
1558 }
1559
1560
1561 void NavigatorTree::DeleteSelection()
1562 {
1563 // of course, i can't delete root
1564 bool bRootSelected = m_xTreeView->is_selected(*m_xRootEntry);
1565 auto nSelectedEntries = m_xTreeView->count_selected_rows();
1566 if (bRootSelected && (nSelectedEntries > 1)) // root and other elements ?
6
Assuming 'bRootSelected' is false
1567 m_xTreeView->unselect(*m_xRootEntry); // yes -> remove root from selection
1568
1569 if ((nSelectedEntries == 0) || bRootSelected
7.1
'bRootSelected' is false
7.1
'bRootSelected' is false
7.1
'bRootSelected' is false
) // still root ?
7
Assuming 'nSelectedEntries' is not equal to 0
8
Taking false branch
1570 return; // -> only selected element -> leave
1571
1572 DBG_ASSERT(!m_bPrevSelectionMixed, "NavigatorTree::DeleteSelection() : delete permitted if mark and selection are inconsistent")do { if (true && (!(!m_bPrevSelectionMixed))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1572" ": "), "%s", "NavigatorTree::DeleteSelection() : delete permitted if mark and selection are inconsistent"
); } } while (false)
;
9
Assuming field 'm_bPrevSelectionMixed' is true
10
Taking true branch
11
Loop condition is false. Exiting loop
1573
1574 // i need the FormModel later
1575 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1576 if (!pFormShell)
12
Assuming 'pFormShell' is non-null
13
Taking false branch
1577 return;
1578 FmFormModel* pFormModel = pFormShell->GetFormModel();
1579 if (!pFormModel)
14
Assuming 'pFormModel' is non-null
15
Taking false branch
1580 return;
1581
1582 // now I have to safeguard the DeleteList: if you delete a form and a dependent element
1583 // - in this order - than the SvLBoxEntryPtr of the dependent element is already invalid,
1584 // when it should be deleted... you have to prohibit this GPF, that of course would happen,
1585 // so I take the 'normalized' list
1586 CollectSelectionData( SDI_NORMALIZED );
1587
1588 // see below for why we need this mapping from models to shapes
1589 FmFormView* pFormView = pFormShell->GetFormView();
1590 SdrPageView* pPageView = pFormView ? pFormView->GetSdrPageView() : nullptr;
16
Assuming 'pFormView' is null
17
'?' condition is false
1591 SdrPage* pPage = pPageView
17.1
'pPageView' is null
17.1
'pPageView' is null
17.1
'pPageView' is null
? pPageView->GetPage() : nullptr;
18
'?' condition is false
1592 DBG_ASSERT( pPage, "NavigatorTree::DeleteSelection: invalid form page!" )do { if (true && (!(pPage))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1592" ": "), "%s", "NavigatorTree::DeleteSelection: invalid form page!"
); } } while (false)
;
19
Taking true branch
20
Loop condition is false. Exiting loop
1593
1594 MapModelToShape aModelShapes;
1595 if ( pPage
20.1
'pPage' is null
20.1
'pPage' is null
20.1
'pPage' is null
)
21
Taking false branch
1596 collectShapeModelMapping( pPage, aModelShapes );
1597
1598 // problem: we have to use ExplorerModel::Remove, since only this one properly deletes Form objects.
1599 // But, the controls themself must be deleted via DeleteMarked (else, the Writer has some problems
1600 // somewhere). In case I'd first delete the structure, then the controls, the UNDO would not work
1601 // (since UNDO then would mean to first restore the controls, then the structure, means their parent
1602 // form). The other way round, the EntryDatas would be invalid, if I'd first delete the controls and
1603 // then go on to the structure. This means I have to delete the forms *after* the normal controls, so
1604 // that during UNDO, they're restored in the proper order.
1605 pFormShell->GetImpl()->EnableTrackProperties_Lock(false);
1606 for (SvLBoxEntrySortedArray::reverse_iterator it = m_arrCurrentSelection.rbegin();
32
Loop condition is true. Entering loop body
1607 it != m_arrCurrentSelection.rend(); )
22
Calling 'operator!=<std::_Rb_tree_const_iterator<std::unique_ptr<weld::TreeIter, std::default_delete<weld::TreeIter>>>>'
31
Returning from 'operator!=<std::_Rb_tree_const_iterator<std::unique_ptr<weld::TreeIter, std::default_delete<weld::TreeIter>>>>'
1608 {
1609 const std::unique_ptr<weld::TreeIter>& rIter = *it;
1610 FmEntryData* pCurrent = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rIter).toInt64());
33
'pCurrent' initialized here
1611
1612 // a form ?
1613 bool bIsForm = dynamic_cast<const FmFormData*>( pCurrent) != nullptr;
34
Assuming the condition is false
35
Assuming pointer value is null
1614
1615 // because deletion is done by the view, and i build on its MarkList,
1616 // but normally only direct controls, no indirect ones, are marked in a marked form,
1617 // I have to do it later
1618 if (bIsForm
35.1
'bIsForm' is false
35.1
'bIsForm' is false
35.1
'bIsForm' is false
)
36
Taking false branch
1619 MarkViewObj(static_cast<FmFormData*>(pCurrent), true/*deep*/);
1620
1621 // a hidden control ?
1622 bool bIsHidden = IsHiddenControl(pCurrent);
37
Calling 'NavigatorTree::IsHiddenControl'
40
Returning from 'NavigatorTree::IsHiddenControl'
1623
1624 // keep forms and hidden controls, the rest not
1625 if (!bIsForm
40.1
'bIsForm' is false
40.1
'bIsForm' is false
40.1
'bIsForm' is false
&& !bIsHidden
40.2
'bIsHidden' is false
40.2
'bIsHidden' is false
40.2
'bIsHidden' is false
)
41
Taking true branch
1626 {
1627 // well, no form and no hidden control -> we can remove it from m_arrCurrentSelection, as it will
1628 // be deleted automatically. This is because for every model (except forms and hidden control models)
1629 // there exist a shape, which is marked _if_and_only_if_ the model is selected in our tree.
1630 if ( aModelShapes.find( pCurrent->GetElement() ) != aModelShapes.end() )
42
Called C++ object pointer is null
1631 {
1632 // if there's a shape for the current entry, then either it is marked or it is in a
1633 // hidden layer (#i28502#), or something like this.
1634 // In the first case, it will be deleted below, in the second case, we currently don't
1635 // delete it, as there's no real (working!) API for this, neither in UNO nor in non-UNO.
1636 m_arrCurrentSelection.erase( --(it.base()) );
1637 }
1638 else
1639 ++it;
1640 // In case there is no shape for the current entry, we keep the entry in m_arrCurrentSelection,
1641 // since then we can definitely remove it.
1642 }
1643 else
1644 ++it;
1645 }
1646 pFormShell->GetImpl()->EnableTrackProperties_Lock(true);
1647
1648 // let the view delete the marked controls
1649 pFormShell->GetFormView()->DeleteMarked();
1650
1651 // start UNDO at this point. Unfortunately, this results in 2 UNDO actions, since DeleteMarked is
1652 // creating an own one. However, if we'd move it before DeleteMarked, Writer does not really like
1653 // this ... :(
1654 // #i31038#
1655 {
1656
1657 // initialize UNDO
1658 OUString aUndoStr;
1659 if ( m_arrCurrentSelection.size() == 1 )
1660 {
1661 aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_REMOVEreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_REMOVE"
"\004" u8"Delete #")
);
1662 if (m_nFormsSelected)
1663 aUndoStr = aUndoStr.replaceFirst( "#", SvxResId( RID_STR_FORMreinterpret_cast<char const *>("RID_STR_FORM" "\004" u8"Form"
)
) );
1664 else
1665 // it must be a control (else the root would be selected, but it cannot be deleted)
1666 aUndoStr = aUndoStr.replaceFirst( "#", SvxResId( RID_STR_CONTROLreinterpret_cast<char const *>("RID_STR_CONTROL" "\004"
u8"Control")
) );
1667 }
1668 else
1669 {
1670 aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_REMOVE_MULTIPLEreinterpret_cast<char const *>("RID_STR_UNDO_CONTAINER_REMOVE_MULTIPLE"
"\004" u8"Delete # objects")
);
1671 aUndoStr = aUndoStr.replaceFirst( "#", OUString::number( m_arrCurrentSelection.size() ) );
1672 }
1673 pFormModel->BegUndo(aUndoStr);
1674 }
1675
1676 // remove remaining structure
1677 for (const auto& rpSelection : m_arrCurrentSelection)
1678 {
1679 FmEntryData* pCurrent = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rpSelection).toInt64());
1680
1681 // if the entry still has children, we skipped deletion of one of those children.
1682 // This may for instance be because the shape is in a hidden layer, where we're unable
1683 // to remove it
1684 if ( pCurrent->GetChildList()->size() )
1685 continue;
1686
1687 // one remaining subtile problem, before deleting it : if it's a form and the shell
1688 // knows it as CurrentObject, I have to tell it something else
1689 if (dynamic_cast<const FmFormData*>( pCurrent) != nullptr)
1690 {
1691 Reference< XForm > xCurrentForm( static_cast< FmFormData* >( pCurrent )->GetFormIface() );
1692 if (pFormShell->GetImpl()->getCurrentForm_Lock() == xCurrentForm) // shell knows form to be deleted ?
1693 pFormShell->GetImpl()->forgetCurrentForm_Lock(); // -> take away ...
1694 }
1695 GetNavModel()->Remove(pCurrent, true);
1696 }
1697 pFormModel->EndUndo();
1698 }
1699
1700
1701 void NavigatorTree::CollectSelectionData(SELDATA_ITEMS sdiHow)
1702 {
1703 DBG_ASSERT(sdiHow != SDI_DIRTY, "NavigatorTree::CollectSelectionData : ever thought about your parameter ? DIRTY ?")do { if (true && (!(sdiHow != SDI_DIRTY))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1703" ": "), "%s", "NavigatorTree::CollectSelectionData : ever thought about your parameter ? DIRTY ?"
); } } while (false)
;
1704 if (sdiHow == m_sdiState)
1705 return;
1706
1707 m_arrCurrentSelection.clear();
1708 m_nFormsSelected = m_nControlsSelected = m_nHiddenControls = 0;
1709 m_bRootSelected = false;
1710
1711 m_xTreeView->selected_foreach([this, sdiHow](weld::TreeIter& rSelectionLoop){
1712 // count different elements
1713 if (m_xTreeView->iter_compare(rSelectionLoop, *m_xRootEntry) == 0)
1714 m_bRootSelected = true;
1715 else
1716 {
1717 if (IsFormEntry(rSelectionLoop))
1718 ++m_nFormsSelected;
1719 else
1720 {
1721 ++m_nControlsSelected;
1722 if (IsHiddenControl(reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rSelectionLoop).toInt64())))
1723 ++m_nHiddenControls;
1724 }
1725 }
1726
1727 if (sdiHow == SDI_NORMALIZED)
1728 {
1729 // don't take something with a selected ancestor
1730 if (m_xTreeView->iter_compare(rSelectionLoop, *m_xRootEntry) == 0)
1731 m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
1732 else
1733 {
1734 std::unique_ptr<weld::TreeIter> xParentLoop(m_xTreeView->make_iterator(&rSelectionLoop));
1735 bool bParentLoop = m_xTreeView->iter_parent(*xParentLoop);
1736 while (bParentLoop)
1737 {
1738 // actually i would have to test, if parent is part of m_arr_CurrentSelection ...
1739 // but if it's selected, then it's in m_arrCurrentSelection
1740 // or one of its ancestors, which was selected earlier.
1741 // In both cases IsSelected is enough
1742 if (m_xTreeView->is_selected(*xParentLoop))
1743 break;
1744 else
1745 {
1746 if (m_xTreeView->iter_compare(*xParentLoop, *m_xRootEntry) == 0)
1747 {
1748 // until root (exclusive), there was no selected parent -> entry belongs to normalized list
1749 m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
1750 break;
1751 }
1752 else
1753 bParentLoop = m_xTreeView->iter_parent(*xParentLoop);
1754 }
1755 }
1756 }
1757 }
1758 else if (sdiHow == SDI_NORMALIZED_FORMARK)
1759 {
1760 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rSelectionLoop));
1761 bool bParent = m_xTreeView->iter_parent(*xParent);
1762 if (!bParent || !m_xTreeView->is_selected(*xParent) || IsFormEntry(rSelectionLoop))
1763 m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
1764 }
1765 else
1766 m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
1767
1768 return false;
1769 });
1770
1771 m_sdiState = sdiHow;
1772 }
1773
1774 void NavigatorTree::SynchronizeSelection(FmEntryDataArray& arredToSelect)
1775 {
1776 LockSelectionHandling();
1777 if (arredToSelect.empty())
1778 {
1779 m_xTreeView->unselect_all();
1780 }
1781 else
1782 {
1783 // compare current selection with requested SelectList
1784 m_xTreeView->selected_foreach([this, &arredToSelect](weld::TreeIter& rSelection) {
1785 FmEntryData* pCurrent = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rSelection).toInt64());
1786 if (pCurrent != nullptr)
1787 {
1788 FmEntryDataArray::iterator it = arredToSelect.find(pCurrent);
1789 if ( it != arredToSelect.end() )
1790 { // entry already selected, but also in SelectList
1791 // remove it from there
1792 arredToSelect.erase(it);
1793 } else
1794 { // entry selected, but not in SelectList -> remove selection
1795 m_xTreeView->unselect(rSelection);
1796 // make it visible (maybe it's the only modification i do in this handler
1797 // so you should see it
1798 m_xTreeView->scroll_to_row(rSelection);
1799 }
1800 }
1801 else
1802 m_xTreeView->unselect(rSelection);
1803
1804 return false;
1805 });
1806
1807 // now SelectList contains only entries, which have to be selected
1808 // two possibilities : 1) run through SelectList, get SvTreeListEntry for every entry and select it (is more intuitive)
1809 // 2) run through my SvLBoxEntries and select those, i can find in the SelectList
1810 // 1) needs =(k*n) (k=length of SelectList, n=number of entries),
1811 // plus the fact, that FindEntry uses extensive IsEqualWithoutChilden instead of comparing pointer to UserData
1812 // 2) needs =(n*log k), duplicates some code from FindEntry
1813 // This may be a frequently used code ( at every change in mark of the view!),
1814 // so i use latter one
1815 m_xTreeView->all_foreach([this, &arredToSelect](weld::TreeIter& rLoop){
1816 FmEntryData* pCurEntryData = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(rLoop).toInt64());
1817 FmEntryDataArray::iterator it = arredToSelect.find(pCurEntryData);
1818 if (it != arredToSelect.end())
1819 {
1820 m_xTreeView->select(rLoop);
1821 m_xTreeView->scroll_to_row(rLoop);
1822 }
1823
1824 return false;
1825 });
1826 }
1827 UnlockSelectionHandling();
1828 }
1829
1830
1831 void NavigatorTree::SynchronizeSelection()
1832 {
1833 // shell and view
1834 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1835 if(!pFormShell) return;
1836
1837 FmFormView* pFormView = pFormShell->GetFormView();
1838 if (!pFormView) return;
1839
1840 GetNavModel()->BroadcastMarkedObjects(pFormView->GetMarkedObjectList());
1841 }
1842
1843
1844 void NavigatorTree::SynchronizeMarkList()
1845 {
1846 // i'll need this shell
1847 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1848 if (!pFormShell) return;
1849
1850 CollectSelectionData(SDI_NORMALIZED_FORMARK);
1851
1852 // the view shouldn't notify now if MarkList changed
1853 pFormShell->GetImpl()->EnableTrackProperties_Lock(false);
1854
1855 UnmarkAllViewObj();
1856
1857 for (auto& rSelectionLoop : m_arrCurrentSelection)
1858 {
1859 // When form selection, mark all controls of form
1860 if (IsFormEntry(*rSelectionLoop) && m_xTreeView->iter_compare(*rSelectionLoop, *m_xRootEntry) != 0)
1861 MarkViewObj(reinterpret_cast<FmFormData*>(m_xTreeView->get_id(*rSelectionLoop).toInt64()), false/*deep*/);
1862
1863 // When control selection, mark Control-SdrObjects
1864 else if (IsFormComponentEntry(*rSelectionLoop))
1865 {
1866 FmControlData* pControlData = reinterpret_cast<FmControlData*>(m_xTreeView->get_id(*rSelectionLoop).toInt64());
1867 if (pControlData)
1868 {
1869
1870 // When HiddenControl no object can be selected
1871 Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent());
1872 if (!xFormComponent.is())
1873 continue;
1874 Reference< XPropertySet > xSet(xFormComponent, UNO_QUERY);
1875 if (!xSet.is())
1876 continue;
1877
1878 sal_uInt16 nClassId = ::comphelper::getINT16(xSet->getPropertyValue(FM_PROP_CLASSID"ClassId"));
1879 if (nClassId != FormComponentType::HIDDENCONTROL)
1880 MarkViewObj(pControlData);
1881 }
1882 }
1883 }
1884
1885 // if PropertyBrowser is open, I have to adopt it according to my selection
1886 // (Not as MarkList of view : if a form is selected, all belonging controls are selected in the view
1887 // but of course i want to see the form-properties
1888 ShowSelectionProperties();
1889
1890 // reset flag at view
1891 pFormShell->GetImpl()->EnableTrackProperties_Lock(true);
1892
1893 // if exactly one form is selected now, shell should notice it as CurrentForm
1894 // (if selection handling isn't locked, view cares about it in MarkListHasChanged
1895 // but mechanism doesn't work, if form is empty for example
1896 if ((m_arrCurrentSelection.size() != 1) || (m_nFormsSelected != 1))
1897 return;
1898
1899 std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
1900 if (!m_xTreeView->get_selected(xSelected.get()))
1901 xSelected.reset();
1902 FmFormData* pSingleSelectionData = xSelected ? dynamic_cast<FmFormData*>(reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*xSelected).toInt64()))
1903 : nullptr;
1904 DBG_ASSERT( pSingleSelectionData, "NavigatorTree::SynchronizeMarkList: invalid selected form!" )do { if (true && (!(pSingleSelectionData))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx"
":" "1904" ": "), "%s", "NavigatorTree::SynchronizeMarkList: invalid selected form!"
); } } while (false)
;
1905 if ( pSingleSelectionData )
1906 {
1907 InterfaceBag aSelection;
1908 aSelection.insert( Reference< XInterface >( pSingleSelectionData->GetFormIface(), UNO_QUERY ) );
1909 pFormShell->GetImpl()->setCurrentSelection_Lock(aSelection);
1910 }
1911 }
1912
1913 bool NavigatorTree::IsHiddenControl(FmEntryData const * pEntryData)
1914 {
1915 if (pEntryData == nullptr) return false;
38
Taking true branch
39
Returning zero, which participates in a condition later
1916
1917 Reference< XPropertySet > xProperties( pEntryData->GetPropertySet() );
1918 if (::comphelper::hasProperty(FM_PROP_CLASSID"ClassId", xProperties))
1919 {
1920 Any aClassID = xProperties->getPropertyValue( FM_PROP_CLASSID"ClassId" );
1921 return (::comphelper::getINT16(aClassID) == FormComponentType::HIDDENCONTROL);
1922 }
1923 return false;
1924 }
1925
1926 void NavigatorTree::UnmarkAllViewObj()
1927 {
1928 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1929 if( !pFormShell )
1930 return;
1931 FmFormView* pFormView = pFormShell->GetFormView();
1932 pFormView->UnMarkAll();
1933 }
1934
1935 void NavigatorTree::MarkViewObj(FmFormData const * pFormData, bool bDeep )
1936 {
1937 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
1938 if( !pFormShell )
1939 return;
1940
1941 // first collect all sdrobjects
1942 ::std::set< Reference< XFormComponent > > aObjects;
1943 CollectObjects(pFormData,bDeep,aObjects);
1944
1945
1946 // find and select appropriate SdrObj in page
1947 FmFormView* pFormView = pFormShell->GetFormView();
1948 SdrPageView* pPageView = pFormView->GetSdrPageView();
1949 SdrPage* pPage = pPageView->GetPage();
1950 //FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage );
1951
1952 SdrObjListIter aIter( pPage );
1953 while ( aIter.IsMore() )
1954 {
1955 SdrObject* pSdrObject = aIter.Next();
1956 FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
1957 if ( !pFormObject )
1958 continue;
1959
1960 Reference< XFormComponent > xControlModel( pFormObject->GetUnoControlModel(),UNO_QUERY );
1961 if ( xControlModel.is() && aObjects.find(xControlModel) != aObjects.end() && !pFormView->IsObjMarked( pSdrObject ) )
1962 {
1963 // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first
1964 pFormView->MarkObj( pSdrObject, pPageView );
1965 }
1966 } // while ( aIter.IsMore() )
1967 // make the mark visible
1968 ::tools::Rectangle aMarkRect( pFormView->GetAllMarkedRect());
1969 for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
1970 {
1971 SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i );
1972 OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
1973 if ( ( OUTDEV_WINDOW == rOutDev.GetOutDevType() ) && !aMarkRect.IsEmpty() )
1974 {
1975 pFormView->MakeVisible( aMarkRect, static_cast<vcl::Window&>(rOutDev) );
1976 }
1977 } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
1978 }
1979
1980 void NavigatorTree::CollectObjects(FmFormData const * pFormData, bool bDeep, ::std::set< Reference< XFormComponent > >& _rObjects)
1981 {
1982 FmEntryDataList* pChildList = pFormData->GetChildList();
1983 FmControlData* pControlData;
1984 for( size_t i = 0; i < pChildList->size(); ++i )
1985 {
1986 FmEntryData* pEntryData = pChildList->at( i );
1987 if( dynamic_cast<const FmControlData*>( pEntryData) != nullptr )
1988 {
1989 pControlData = static_cast<FmControlData*>(pEntryData);
1990 _rObjects.insert(pControlData->GetFormComponent());
1991 } // if( dynamic_cast<const FmControlData*>( pEntryData) != nullptr )
1992 else if (bDeep && (dynamic_cast<const FmFormData*>( pEntryData) != nullptr))
1993 CollectObjects(static_cast<FmFormData*>(pEntryData), bDeep, _rObjects);
1994 } // for( sal_uInt32 i=0; i<pChildList->Count(); i++ )
1995 }
1996
1997 void NavigatorTree::MarkViewObj( FmControlData const * pControlData)
1998 {
1999 if( !pControlData )
2000 return;
2001 FmFormShell* pFormShell = GetNavModel()->GetFormShell();
2002 if( !pFormShell )
2003 return;
2004
2005
2006 // find and select appropriate SdrObj
2007 FmFormView* pFormView = pFormShell->GetFormView();
2008 Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent());
2009 SdrPageView* pPageView = pFormView->GetSdrPageView();
2010 SdrPage* pPage = pPageView->GetPage();
2011
2012 bool bPaint = false;
2013 SdrObjListIter aIter( pPage );
2014 while ( aIter.IsMore() )
2015 {
2016 SdrObject* pSdrObject = aIter.Next();
2017 FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
2018 if ( !pFormObject )
2019 continue;
2020
2021 Reference< XInterface > xControlModel( pFormObject->GetUnoControlModel() );
2022 if ( xControlModel != xFormComponent )
2023 continue;
2024
2025 // mark the object
2026 if ( !pFormView->IsObjMarked( pSdrObject ) )
2027 // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first
2028 pFormView->MarkObj( pSdrObject, pPageView );
2029
2030 bPaint = true;
2031
2032 } // while ( aIter.IsMore() )
2033 if ( !bPaint )
2034 return;
2035
2036 // make the mark visible
2037 ::tools::Rectangle aMarkRect( pFormView->GetAllMarkedRect());
2038 for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
2039 {
2040 SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i );
2041 OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
2042 if ( OUTDEV_WINDOW == rOutDev.GetOutDevType() )
2043 {
2044 pFormView->MakeVisible( aMarkRect, static_cast<vcl::Window&>(rOutDev) );
2045 }
2046 } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
2047 }
2048
2049
2050}
2051
2052
2053/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/stl_iterator.h

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
85namespace 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(); }
24
Calling 'operator=='
27
Returning from 'operator=='
28
Returning zero, which participates in a condition later
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); }
23
Calling 'operator==<std::_Rb_tree_const_iterator<std::unique_ptr<weld::TreeIter, std::default_delete<weld::TreeIter>>>>'
29
Returning from 'operator==<std::_Rb_tree_const_iterator<std::unique_ptr<weld::TreeIter, std::default_delete<weld::TreeIter>>>>'
30
Returning the value 1, which participates in a condition later
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
918namespace __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
1193namespace 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

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/stl_tree.h

1// RB tree implementation -*- 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) 1996,1997
28 * Silicon Graphics Computer Systems, Inc.
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. Silicon Graphics 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) 1994
40 * Hewlett-Packard Company
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. Hewlett-Packard Company 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 */
52
53/** @file bits/stl_tree.h
54 * This is an internal header file, included by other library headers.
55 * Do not attempt to use it directly. @headername{map,set}
56 */
57
58#ifndef _STL_TREE_H1
59#define _STL_TREE_H1 1
60
61#pragma GCC system_header
62
63#include <bits/stl_algobase.h>
64#include <bits/allocator.h>
65#include <bits/stl_function.h>
66#include <bits/cpp_type_traits.h>
67#include <ext/alloc_traits.h>
68#if __cplusplus201703L >= 201103L
69# include <ext/aligned_buffer.h>
70#endif
71#if __cplusplus201703L > 201402L
72# include <bits/node_handle.h>
73#endif
74
75namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
76{
77_GLIBCXX_BEGIN_NAMESPACE_VERSION
78
79#if __cplusplus201703L > 201103L
80# define __cpp_lib_generic_associative_lookup201304 201304
81#endif
82
83 // Red-black tree class, designed for use in implementing STL
84 // associative containers (set, multiset, map, and multimap). The
85 // insertion and deletion algorithms are based on those in Cormen,
86 // Leiserson, and Rivest, Introduction to Algorithms (MIT Press,
87 // 1990), except that
88 //
89 // (1) the header cell is maintained with links not only to the root
90 // but also to the leftmost node of the tree, to enable constant
91 // time begin(), and to the rightmost node of the tree, to enable
92 // linear time performance when used with the generic set algorithms
93 // (set_union, etc.)
94 //
95 // (2) when a node being deleted has two children its successor node
96 // is relinked into its place, rather than copied, so that the only
97 // iterators invalidated are those referring to the deleted node.
98
99 enum _Rb_tree_color { _S_red = false, _S_black = true };
100
101 struct _Rb_tree_node_base
102 {
103 typedef _Rb_tree_node_base* _Base_ptr;
104 typedef const _Rb_tree_node_base* _Const_Base_ptr;
105
106 _Rb_tree_color _M_color;
107 _Base_ptr _M_parent;
108 _Base_ptr _M_left;
109 _Base_ptr _M_right;
110
111 static _Base_ptr
112 _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
113 {
114 while (__x->_M_left != 0) __x = __x->_M_left;
115 return __x;
116 }
117
118 static _Const_Base_ptr
119 _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
120 {
121 while (__x->_M_left != 0) __x = __x->_M_left;
122 return __x;
123 }
124
125 static _Base_ptr
126 _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
127 {
128 while (__x->_M_right != 0) __x = __x->_M_right;
129 return __x;
130 }
131
132 static _Const_Base_ptr
133 _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
134 {
135 while (__x->_M_right != 0) __x = __x->_M_right;
136 return __x;
137 }
138 };
139
140 // Helper type offering value initialization guarantee on the compare functor.
141 template<typename _Key_compare>
142 struct _Rb_tree_key_compare
143 {
144 _Key_compare _M_key_compare;
145
146 _Rb_tree_key_compare()
147 _GLIBCXX_NOEXCEPT_IF(noexcept(is_nothrow_default_constructible<_Key_compare>
::value)
148 is_nothrow_default_constructible<_Key_compare>::value)noexcept(is_nothrow_default_constructible<_Key_compare>
::value)
149 : _M_key_compare()
150 { }
151
152 _Rb_tree_key_compare(const _Key_compare& __comp)
153 : _M_key_compare(__comp)
154 { }
155
156#if __cplusplus201703L >= 201103L
157 // Copy constructor added for consistency with C++98 mode.
158 _Rb_tree_key_compare(const _Rb_tree_key_compare&) = default;
159
160 _Rb_tree_key_compare(_Rb_tree_key_compare&& __x)
161 noexcept(is_nothrow_copy_constructible<_Key_compare>::value)
162 : _M_key_compare(__x._M_key_compare)
163 { }
164#endif
165 };
166
167 // Helper type to manage default initialization of node count and header.
168 struct _Rb_tree_header
169 {
170 _Rb_tree_node_base _M_header;
171 size_t _M_node_count; // Keeps track of size of tree.
172
173 _Rb_tree_header() _GLIBCXX_NOEXCEPTnoexcept
174 {
175 _M_header._M_color = _S_red;
176 _M_reset();
177 }
178
179#if __cplusplus201703L >= 201103L
180 _Rb_tree_header(_Rb_tree_header&& __x) noexcept
181 {
182 if (__x._M_header._M_parent != nullptr)
183 _M_move_data(__x);
184 else
185 {
186 _M_header._M_color = _S_red;
187 _M_reset();
188 }
189 }
190#endif
191
192 void
193 _M_move_data(_Rb_tree_header& __from)
194 {
195 _M_header._M_color = __from._M_header._M_color;
196 _M_header._M_parent = __from._M_header._M_parent;
197 _M_header._M_left = __from._M_header._M_left;
198 _M_header._M_right = __from._M_header._M_right;
199 _M_header._M_parent->_M_parent = &_M_header;
200 _M_node_count = __from._M_node_count;
201
202 __from._M_reset();
203 }
204
205 void
206 _M_reset()
207 {
208 _M_header._M_parent = 0;
209 _M_header._M_left = &_M_header;
210 _M_header._M_right = &_M_header;
211 _M_node_count = 0;
212 }
213 };
214
215 template<typename _Val>
216 struct _Rb_tree_node : public _Rb_tree_node_base
217 {
218 typedef _Rb_tree_node<_Val>* _Link_type;
219
220#if __cplusplus201703L < 201103L
221 _Val _M_value_field;
222
223 _Val*
224 _M_valptr()
225 { return std::__addressof(_M_value_field); }
226
227 const _Val*
228 _M_valptr() const
229 { return std::__addressof(_M_value_field); }
230#else
231 __gnu_cxx::__aligned_membuf<_Val> _M_storage;
232
233 _Val*
234 _M_valptr()
235 { return _M_storage._M_ptr(); }
236
237 const _Val*
238 _M_valptr() const
239 { return _M_storage._M_ptr(); }
240#endif
241 };
242
243 _GLIBCXX_PURE__attribute__ ((__pure__)) _Rb_tree_node_base*
244 _Rb_tree_increment(_Rb_tree_node_base* __x) throw ();
245
246 _GLIBCXX_PURE__attribute__ ((__pure__)) const _Rb_tree_node_base*
247 _Rb_tree_increment(const _Rb_tree_node_base* __x) throw ();
248
249 _GLIBCXX_PURE__attribute__ ((__pure__)) _Rb_tree_node_base*
250 _Rb_tree_decrement(_Rb_tree_node_base* __x) throw ();
251
252 _GLIBCXX_PURE__attribute__ ((__pure__)) const _Rb_tree_node_base*
253 _Rb_tree_decrement(const _Rb_tree_node_base* __x) throw ();
254
255 template<typename _Tp>
256 struct _Rb_tree_iterator
257 {
258 typedef _Tp value_type;
259 typedef _Tp& reference;
260 typedef _Tp* pointer;
261
262 typedef bidirectional_iterator_tag iterator_category;
263 typedef ptrdiff_t difference_type;
264
265 typedef _Rb_tree_iterator<_Tp> _Self;
266 typedef _Rb_tree_node_base::_Base_ptr _Base_ptr;
267 typedef _Rb_tree_node<_Tp>* _Link_type;
268
269 _Rb_tree_iterator() _GLIBCXX_NOEXCEPTnoexcept
270 : _M_node() { }
271
272 explicit
273 _Rb_tree_iterator(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
274 : _M_node(__x) { }
275
276 reference
277 operator*() const _GLIBCXX_NOEXCEPTnoexcept
278 { return *static_cast<_Link_type>(_M_node)->_M_valptr(); }
279
280 pointer
281 operator->() const _GLIBCXX_NOEXCEPTnoexcept
282 { return static_cast<_Link_type> (_M_node)->_M_valptr(); }
283
284 _Self&
285 operator++() _GLIBCXX_NOEXCEPTnoexcept
286 {
287 _M_node = _Rb_tree_increment(_M_node);
288 return *this;
289 }
290
291 _Self
292 operator++(int) _GLIBCXX_NOEXCEPTnoexcept
293 {
294 _Self __tmp = *this;
295 _M_node = _Rb_tree_increment(_M_node);
296 return __tmp;
297 }
298
299 _Self&
300 operator--() _GLIBCXX_NOEXCEPTnoexcept
301 {
302 _M_node = _Rb_tree_decrement(_M_node);
303 return *this;
304 }
305
306 _Self
307 operator--(int) _GLIBCXX_NOEXCEPTnoexcept
308 {
309 _Self __tmp = *this;
310 _M_node = _Rb_tree_decrement(_M_node);
311 return __tmp;
312 }
313
314 friend bool
315 operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPTnoexcept
316 { return __x._M_node == __y._M_node; }
317
318#if ! __cpp_lib_three_way_comparison
319 friend bool
320 operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPTnoexcept
321 { return __x._M_node != __y._M_node; }
322#endif
323
324 _Base_ptr _M_node;
325 };
326
327 template<typename _Tp>
328 struct _Rb_tree_const_iterator
329 {
330 typedef _Tp value_type;
331 typedef const _Tp& reference;
332 typedef const _Tp* pointer;
333
334 typedef _Rb_tree_iterator<_Tp> iterator;
335
336 typedef bidirectional_iterator_tag iterator_category;
337 typedef ptrdiff_t difference_type;
338
339 typedef _Rb_tree_const_iterator<_Tp> _Self;
340 typedef _Rb_tree_node_base::_Const_Base_ptr _Base_ptr;
341 typedef const _Rb_tree_node<_Tp>* _Link_type;
342
343 _Rb_tree_const_iterator() _GLIBCXX_NOEXCEPTnoexcept
344 : _M_node() { }
345
346 explicit
347 _Rb_tree_const_iterator(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
348 : _M_node(__x) { }
349
350 _Rb_tree_const_iterator(const iterator& __it) _GLIBCXX_NOEXCEPTnoexcept
351 : _M_node(__it._M_node) { }
352
353 iterator
354 _M_const_cast() const _GLIBCXX_NOEXCEPTnoexcept
355 { return iterator(const_cast<typename iterator::_Base_ptr>(_M_node)); }
356
357 reference
358 operator*() const _GLIBCXX_NOEXCEPTnoexcept
359 { return *static_cast<_Link_type>(_M_node)->_M_valptr(); }
360
361 pointer
362 operator->() const _GLIBCXX_NOEXCEPTnoexcept
363 { return static_cast<_Link_type>(_M_node)->_M_valptr(); }
364
365 _Self&
366 operator++() _GLIBCXX_NOEXCEPTnoexcept
367 {
368 _M_node = _Rb_tree_increment(_M_node);
369 return *this;
370 }
371
372 _Self
373 operator++(int) _GLIBCXX_NOEXCEPTnoexcept
374 {
375 _Self __tmp = *this;
376 _M_node = _Rb_tree_increment(_M_node);
377 return __tmp;
378 }
379
380 _Self&
381 operator--() _GLIBCXX_NOEXCEPTnoexcept
382 {
383 _M_node = _Rb_tree_decrement(_M_node);
384 return *this;
385 }
386
387 _Self
388 operator--(int) _GLIBCXX_NOEXCEPTnoexcept
389 {
390 _Self __tmp = *this;
391 _M_node = _Rb_tree_decrement(_M_node);
392 return __tmp;
393 }
394
395 friend bool
396 operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPTnoexcept
397 { return __x._M_node == __y._M_node; }
25
Assuming '__x._M_node' is not equal to '__y._M_node'
26
Returning zero, which participates in a condition later
398
399#if ! __cpp_lib_three_way_comparison
400 friend bool
401 operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPTnoexcept
402 { return __x._M_node != __y._M_node; }
403#endif
404
405 _Base_ptr _M_node;
406 };
407
408 void
409 _Rb_tree_insert_and_rebalance(const bool __insert_left,
410 _Rb_tree_node_base* __x,
411 _Rb_tree_node_base* __p,
412 _Rb_tree_node_base& __header) throw ();
413
414 _Rb_tree_node_base*
415 _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* const __z,
416 _Rb_tree_node_base& __header) throw ();
417
418#if __cplusplus201703L >= 201402L
419 template<typename _Cmp, typename _SfinaeType, typename = __void_t<>>
420 struct __has_is_transparent
421 { };
422
423 template<typename _Cmp, typename _SfinaeType>
424 struct __has_is_transparent<_Cmp, _SfinaeType,
425 __void_t<typename _Cmp::is_transparent>>
426 { typedef void type; };
427
428 template<typename _Cmp, typename _SfinaeType>
429 using __has_is_transparent_t
430 = typename __has_is_transparent<_Cmp, _SfinaeType>::type;
431#endif
432
433#if __cplusplus201703L > 201402L
434 template<typename _Tree1, typename _Cmp2>
435 struct _Rb_tree_merge_helper { };
436#endif
437
438 template<typename _Key, typename _Val, typename _KeyOfValue,
439 typename _Compare, typename _Alloc = allocator<_Val> >
440 class _Rb_tree
441 {
442 typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
443 rebind<_Rb_tree_node<_Val> >::other _Node_allocator;
444
445 typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits;
446
447 protected:
448 typedef _Rb_tree_node_base* _Base_ptr;
449 typedef const _Rb_tree_node_base* _Const_Base_ptr;
450 typedef _Rb_tree_node<_Val>* _Link_type;
451 typedef const _Rb_tree_node<_Val>* _Const_Link_type;
452
453 private:
454 // Functor recycling a pool of nodes and using allocation once the pool
455 // is empty.
456 struct _Reuse_or_alloc_node
457 {
458 _Reuse_or_alloc_node(_Rb_tree& __t)
459 : _M_root(__t._M_root()), _M_nodes(__t._M_rightmost()), _M_t(__t)
460 {
461 if (_M_root)
462 {
463 _M_root->_M_parent = 0;
464
465 if (_M_nodes->_M_left)
466 _M_nodes = _M_nodes->_M_left;
467 }
468 else
469 _M_nodes = 0;
470 }
471
472#if __cplusplus201703L >= 201103L
473 _Reuse_or_alloc_node(const _Reuse_or_alloc_node&) = delete;
474#endif
475
476 ~_Reuse_or_alloc_node()
477 { _M_t._M_erase(static_cast<_Link_type>(_M_root)); }
478
479 template<typename _Arg>
480 _Link_type
481#if __cplusplus201703L < 201103L
482 operator()(const _Arg& __arg)
483#else
484 operator()(_Arg&& __arg)
485#endif
486 {
487 _Link_type __node = static_cast<_Link_type>(_M_extract());
488 if (__node)
489 {
490 _M_t._M_destroy_node(__node);
491 _M_t._M_construct_node(__node, _GLIBCXX_FORWARD(_Arg, __arg)std::forward<_Arg>(__arg));
492 return __node;
493 }
494
495 return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)std::forward<_Arg>(__arg));
496 }
497
498 private:
499 _Base_ptr
500 _M_extract()
501 {
502 if (!_M_nodes)
503 return _M_nodes;
504
505 _Base_ptr __node = _M_nodes;
506 _M_nodes = _M_nodes->_M_parent;
507 if (_M_nodes)
508 {
509 if (_M_nodes->_M_right == __node)
510 {
511 _M_nodes->_M_right = 0;
512
513 if (_M_nodes->_M_left)
514 {
515 _M_nodes = _M_nodes->_M_left;
516
517 while (_M_nodes->_M_right)
518 _M_nodes = _M_nodes->_M_right;
519
520 if (_M_nodes->_M_left)
521 _M_nodes = _M_nodes->_M_left;
522 }
523 }
524 else // __node is on the left.
525 _M_nodes->_M_left = 0;
526 }
527 else
528 _M_root = 0;
529
530 return __node;
531 }
532
533 _Base_ptr _M_root;
534 _Base_ptr _M_nodes;
535 _Rb_tree& _M_t;
536 };
537
538 // Functor similar to the previous one but without any pool of nodes to
539 // recycle.
540 struct _Alloc_node
541 {
542 _Alloc_node(_Rb_tree& __t)
543 : _M_t(__t) { }
544
545 template<typename _Arg>
546 _Link_type
547#if __cplusplus201703L < 201103L
548 operator()(const _Arg& __arg) const
549#else
550 operator()(_Arg&& __arg) const
551#endif
552 { return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)std::forward<_Arg>(__arg)); }
553
554 private:
555 _Rb_tree& _M_t;
556 };
557
558 public:
559 typedef _Key key_type;
560 typedef _Val value_type;
561 typedef value_type* pointer;
562 typedef const value_type* const_pointer;
563 typedef value_type& reference;
564 typedef const value_type& const_reference;
565 typedef size_t size_type;
566 typedef ptrdiff_t difference_type;
567 typedef _Alloc allocator_type;
568
569 _Node_allocator&
570 _M_get_Node_allocator() _GLIBCXX_NOEXCEPTnoexcept
571 { return this->_M_impl; }
572
573 const _Node_allocator&
574 _M_get_Node_allocator() const _GLIBCXX_NOEXCEPTnoexcept
575 { return this->_M_impl; }
576
577 allocator_type
578 get_allocator() const _GLIBCXX_NOEXCEPTnoexcept
579 { return allocator_type(_M_get_Node_allocator()); }
580
581 protected:
582 _Link_type
583 _M_get_node()
584 { return _Alloc_traits::allocate(_M_get_Node_allocator(), 1); }
585
586 void
587 _M_put_node(_Link_type __p) _GLIBCXX_NOEXCEPTnoexcept
588 { _Alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); }
589
590#if __cplusplus201703L < 201103L
591 void
592 _M_construct_node(_Link_type __node, const value_type& __x)
593 {
594 __trytry
595 { get_allocator().construct(__node->_M_valptr(), __x); }
596 __catch(...)catch(...)
597 {
598 _M_put_node(__node);
599 __throw_exception_againthrow;
600 }
601 }
602
603 _Link_type
604 _M_create_node(const value_type& __x)
605 {
606 _Link_type __tmp = _M_get_node();
607 _M_construct_node(__tmp, __x);
608 return __tmp;
609 }
610#else
611 template<typename... _Args>
612 void
613 _M_construct_node(_Link_type __node, _Args&&... __args)
614 {
615 __trytry
616 {
617 ::new(__node) _Rb_tree_node<_Val>;
618 _Alloc_traits::construct(_M_get_Node_allocator(),
619 __node->_M_valptr(),
620 std::forward<_Args>(__args)...);
621 }
622 __catch(...)catch(...)
623 {
624 __node->~_Rb_tree_node<_Val>();
625 _M_put_node(__node);
626 __throw_exception_againthrow;
627 }
628 }
629
630 template<typename... _Args>
631 _Link_type
632 _M_create_node(_Args&&... __args)
633 {
634 _Link_type __tmp = _M_get_node();
635 _M_construct_node(__tmp, std::forward<_Args>(__args)...);
636 return __tmp;
637 }
638#endif
639
640 void
641 _M_destroy_node(_Link_type __p) _GLIBCXX_NOEXCEPTnoexcept
642 {
643#if __cplusplus201703L < 201103L
644 get_allocator().destroy(__p->_M_valptr());
645#else
646 _Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr());
647 __p->~_Rb_tree_node<_Val>();
648#endif
649 }
650
651 void
652 _M_drop_node(_Link_type __p) _GLIBCXX_NOEXCEPTnoexcept
653 {
654 _M_destroy_node(__p);
655 _M_put_node(__p);
656 }
657
658 template<typename _NodeGen>
659 _Link_type
660 _M_clone_node(_Const_Link_type __x, _NodeGen& __node_gen)
661 {
662 _Link_type __tmp = __node_gen(*__x->_M_valptr());
663 __tmp->_M_color = __x->_M_color;
664 __tmp->_M_left = 0;
665 __tmp->_M_right = 0;
666 return __tmp;
667 }
668
669 protected:
670#if _GLIBCXX_INLINE_VERSION0
671 template<typename _Key_compare>
672#else
673 // Unused _Is_pod_comparator is kept as it is part of mangled name.
674 template<typename _Key_compare,
675 bool /* _Is_pod_comparator */ = __is_pod(_Key_compare)>
676#endif
677 struct _Rb_tree_impl
678 : public _Node_allocator
679 , public _Rb_tree_key_compare<_Key_compare>
680 , public _Rb_tree_header
681 {
682 typedef _Rb_tree_key_compare<_Key_compare> _Base_key_compare;
683
684 _Rb_tree_impl()
685 _GLIBCXX_NOEXCEPT_IF(noexcept(is_nothrow_default_constructible<_Node_allocator>
::value && is_nothrow_default_constructible<_Base_key_compare
>::value)
686 is_nothrow_default_constructible<_Node_allocator>::valuenoexcept(is_nothrow_default_constructible<_Node_allocator>
::value && is_nothrow_default_constructible<_Base_key_compare
>::value)
687 && is_nothrow_default_constructible<_Base_key_compare>::value )noexcept(is_nothrow_default_constructible<_Node_allocator>
::value && is_nothrow_default_constructible<_Base_key_compare
>::value)
688 : _Node_allocator()
689 { }
690
691 _Rb_tree_impl(const _Rb_tree_impl& __x)
692 : _Node_allocator(_Alloc_traits::_S_select_on_copy(__x))
693 , _Base_key_compare(__x._M_key_compare)
694 { }
695
696#if __cplusplus201703L < 201103L
697 _Rb_tree_impl(const _Key_compare& __comp, const _Node_allocator& __a)
698 : _Node_allocator(__a), _Base_key_compare(__comp)
699 { }
700#else
701 _Rb_tree_impl(_Rb_tree_impl&&) = default;
702
703 explicit
704 _Rb_tree_impl(_Node_allocator&& __a)
705 : _Node_allocator(std::move(__a))
706 { }
707
708 _Rb_tree_impl(_Rb_tree_impl&& __x, _Node_allocator&& __a)
709 : _Node_allocator(std::move(__a)),
710 _Base_key_compare(std::move(__x)),
711 _Rb_tree_header(std::move(__x))
712 { }
713
714 _Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a)
715 : _Node_allocator(std::move(__a)), _Base_key_compare(__comp)
716 { }
717#endif
718 };
719
720 _Rb_tree_impl<_Compare> _M_impl;
721
722 protected:
723 _Base_ptr&
724 _M_root() _GLIBCXX_NOEXCEPTnoexcept
725 { return this->_M_impl._M_header._M_parent; }
726
727 _Const_Base_ptr
728 _M_root() const _GLIBCXX_NOEXCEPTnoexcept
729 { return this->_M_impl._M_header._M_parent; }
730
731 _Base_ptr&
732 _M_leftmost() _GLIBCXX_NOEXCEPTnoexcept
733 { return this->_M_impl._M_header._M_left; }
734
735 _Const_Base_ptr
736 _M_leftmost() const _GLIBCXX_NOEXCEPTnoexcept
737 { return this->_M_impl._M_header._M_left; }
738
739 _Base_ptr&
740 _M_rightmost() _GLIBCXX_NOEXCEPTnoexcept
741 { return this->_M_impl._M_header._M_right; }
742
743 _Const_Base_ptr
744 _M_rightmost() const _GLIBCXX_NOEXCEPTnoexcept
745 { return this->_M_impl._M_header._M_right; }
746
747 _Link_type
748 _M_begin() _GLIBCXX_NOEXCEPTnoexcept
749 { return static_cast<_Link_type>(this->_M_impl._M_header._M_parent); }
750
751 _Const_Link_type
752 _M_begin() const _GLIBCXX_NOEXCEPTnoexcept
753 {
754 return static_cast<_Const_Link_type>
755 (this->_M_impl._M_header._M_parent);
756 }
757
758 _Base_ptr
759 _M_end() _GLIBCXX_NOEXCEPTnoexcept
760 { return &this->_M_impl._M_header; }
761
762 _Const_Base_ptr
763 _M_end() const _GLIBCXX_NOEXCEPTnoexcept
764 { return &this->_M_impl._M_header; }
765
766 static const _Key&
767 _S_key(_Const_Link_type __x)
768 {
769#if __cplusplus201703L >= 201103L
770 // If we're asking for the key we're presumably using the comparison
771 // object, and so this is a good place to sanity check it.
772 static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
773 "comparison object must be invocable "
774 "with two arguments of key type");
775# if __cplusplus201703L >= 201703L
776 // _GLIBCXX_RESOLVE_LIB_DEFECTS
777 // 2542. Missing const requirements for associative containers
778 if constexpr (__is_invocable<_Compare&, const _Key&, const _Key&>{})
779 static_assert(
780 is_invocable_v<const _Compare&, const _Key&, const _Key&>,
781 "comparison object must be invocable as const");
782# endif // C++17
783#endif // C++11
784
785 return _KeyOfValue()(*__x->_M_valptr());
786 }
787
788 static _Link_type
789 _S_left(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
790 { return static_cast<_Link_type>(__x->_M_left); }
791
792 static _Const_Link_type
793 _S_left(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
794 { return static_cast<_Const_Link_type>(__x->_M_left); }
795
796 static _Link_type
797 _S_right(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
798 { return static_cast<_Link_type>(__x->_M_right); }
799
800 static _Const_Link_type
801 _S_right(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
802 { return static_cast<_Const_Link_type>(__x->_M_right); }
803
804 static const _Key&
805 _S_key(_Const_Base_ptr __x)
806 { return _S_key(static_cast<_Const_Link_type>(__x)); }
807
808 static _Base_ptr
809 _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
810 { return _Rb_tree_node_base::_S_minimum(__x); }
811
812 static _Const_Base_ptr
813 _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
814 { return _Rb_tree_node_base::_S_minimum(__x); }
815
816 static _Base_ptr
817 _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
818 { return _Rb_tree_node_base::_S_maximum(__x); }
819
820 static _Const_Base_ptr
821 _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPTnoexcept
822 { return _Rb_tree_node_base::_S_maximum(__x); }
823
824 public:
825 typedef _Rb_tree_iterator<value_type> iterator;
826 typedef _Rb_tree_const_iterator<value_type> const_iterator;
827
828 typedef std::reverse_iterator<iterator> reverse_iterator;
829 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
830
831#if __cplusplus201703L > 201402L
832 using node_type = _Node_handle<_Key, _Val, _Node_allocator>;
833 using insert_return_type = _Node_insert_return<
834 conditional_t<is_same_v<_Key, _Val>, const_iterator, iterator>,
835 node_type>;
836#endif
837
838 pair<_Base_ptr, _Base_ptr>
839 _M_get_insert_unique_pos(const key_type& __k);
840
841 pair<_Base_ptr, _Base_ptr>
842 _M_get_insert_equal_pos(const key_type& __k);
843
844 pair<_Base_ptr, _Base_ptr>
845 _M_get_insert_hint_unique_pos(const_iterator __pos,
846 const key_type& __k);
847
848 pair<_Base_ptr, _Base_ptr>
849 _M_get_insert_hint_equal_pos(const_iterator __pos,
850 const key_type& __k);
851
852 private:
853#if __cplusplus201703L >= 201103L
854 template<typename _Arg, typename _NodeGen>
855 iterator
856 _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v, _NodeGen&);
857
858 iterator
859 _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Link_type __z);
860
861 template<typename _Arg>
862 iterator
863 _M_insert_lower(_Base_ptr __y, _Arg&& __v);
864
865 template<typename _Arg>
866 iterator
867 _M_insert_equal_lower(_Arg&& __x);
868
869 iterator
870 _M_insert_lower_node(_Base_ptr __p, _Link_type __z);
871
872 iterator
873 _M_insert_equal_lower_node(_Link_type __z);
874#else
875 template<typename _NodeGen>
876 iterator
877 _M_insert_(_Base_ptr __x, _Base_ptr __y,
878 const value_type& __v, _NodeGen&);
879
880 // _GLIBCXX_RESOLVE_LIB_DEFECTS
881 // 233. Insertion hints in associative containers.
882 iterator
883 _M_insert_lower(_Base_ptr __y, const value_type& __v);
884
885 iterator
886 _M_insert_equal_lower(const value_type& __x);
887#endif
888
889 template<typename _NodeGen>
890 _Link_type
891 _M_copy(_Const_Link_type __x, _Base_ptr __p, _NodeGen&);
892
893 template<typename _NodeGen>
894 _Link_type
895 _M_copy(const _Rb_tree& __x, _NodeGen& __gen)
896 {
897 _Link_type __root = _M_copy(__x._M_begin(), _M_end(), __gen);
898 _M_leftmost() = _S_minimum(__root);
899 _M_rightmost() = _S_maximum(__root);
900 _M_impl._M_node_count = __x._M_impl._M_node_count;
901 return __root;
902 }
903
904 _Link_type
905 _M_copy(const _Rb_tree& __x)
906 {
907 _Alloc_node __an(*this);
908 return _M_copy(__x, __an);
909 }
910
911 void
912 _M_erase(_Link_type __x);
913
914 iterator
915 _M_lower_bound(_Link_type __x, _Base_ptr __y,
916 const _Key& __k);
917
918 const_iterator
919 _M_lower_bound(_Const_Link_type __x, _Const_Base_ptr __y,
920 const _Key& __k) const;
921
922 iterator
923 _M_upper_bound(_Link_type __x, _Base_ptr __y,
924 const _Key& __k);
925
926 const_iterator
927 _M_upper_bound(_Const_Link_type __x, _Const_Base_ptr __y,
928 const _Key& __k) const;
929
930 public:
931 // allocation/deallocation
932#if __cplusplus201703L < 201103L
933 _Rb_tree() { }
934#else
935 _Rb_tree() = default;
936#endif
937
938 _Rb_tree(const _Compare& __comp,
939 const allocator_type& __a = allocator_type())
940 : _M_impl(__comp, _Node_allocator(__a)) { }
941
942 _Rb_tree(const _Rb_tree& __x)
943 : _M_impl(__x._M_impl)
944 {
945 if (__x._M_root() != 0)
946 _M_root() = _M_copy(__x);
947 }
948
949#if __cplusplus201703L >= 201103L
950 _Rb_tree(const allocator_type& __a)
951 : _M_impl(_Node_allocator(__a))
952 { }
953
954 _Rb_tree(const _Rb_tree& __x, const allocator_type& __a)
955 : _M_impl(__x._M_impl._M_key_compare, _Node_allocator(__a))
956 {
957 if (__x._M_root() != nullptr)
958 _M_root() = _M_copy(__x);
959 }
960
961 _Rb_tree(_Rb_tree&&) = default;
962
963 _Rb_tree(_Rb_tree&& __x, const allocator_type& __a)
964 : _Rb_tree(std::move(__x), _Node_allocator(__a))
965 { }
966
967 private:
968 _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a, true_type)
969 noexcept(is_nothrow_default_constructible<_Compare>::value)
970 : _M_impl(std::move(__x._M_impl), std::move(__a))
971 { }
972
973 _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a, false_type)
974 : _M_impl(__x._M_impl._M_key_compare, std::move(__a))
975 {
976 if (__x._M_root() != nullptr)
977 _M_move_data(__x, false_type{});
978 }
979
980 public:
981 _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a)
982 noexcept( noexcept(
983 _Rb_tree(std::declval<_Rb_tree&&>(), std::declval<_Node_allocator&&>(),
984 std::declval<typename _Alloc_traits::is_always_equal>())) )
985 : _Rb_tree(std::move(__x), std::move(__a),
986 typename _Alloc_traits::is_always_equal{})
987 { }
988#endif
989
990 ~_Rb_tree() _GLIBCXX_NOEXCEPTnoexcept
991 { _M_erase(_M_begin()); }
992
993 _Rb_tree&
994 operator=(const _Rb_tree& __x);
995
996 // Accessors.
997 _Compare
998 key_comp() const
999 { return _M_impl._M_key_compare; }
1000
1001 iterator
1002 begin() _GLIBCXX_NOEXCEPTnoexcept
1003 { return iterator(this->_M_impl._M_header._M_left); }
1004
1005 const_iterator
1006 begin() const _GLIBCXX_NOEXCEPTnoexcept
1007 { return const_iterator(this->_M_impl._M_header._M_left); }
1008
1009 iterator
1010 end() _GLIBCXX_NOEXCEPTnoexcept
1011 { return iterator(&this->_M_impl._M_header); }
1012
1013 const_iterator
1014 end() const _GLIBCXX_NOEXCEPTnoexcept
1015 { return const_iterator(&this->_M_impl._M_header); }
1016
1017 reverse_iterator
1018 rbegin() _GLIBCXX_NOEXCEPTnoexcept
1019 { return reverse_iterator(end()); }
1020
1021 const_reverse_iterator
1022 rbegin() const _GLIBCXX_NOEXCEPTnoexcept
1023 { return const_reverse_iterator(end()); }
1024
1025 reverse_iterator
1026 rend() _GLIBCXX_NOEXCEPTnoexcept
1027 { return reverse_iterator(begin()); }
1028
1029 const_reverse_iterator
1030 rend() const _GLIBCXX_NOEXCEPTnoexcept
1031 { return const_reverse_iterator(begin()); }
1032
1033 _GLIBCXX_NODISCARD[[__nodiscard__]] bool
1034 empty() const _GLIBCXX_NOEXCEPTnoexcept
1035 { return _M_impl._M_node_count == 0; }
1036
1037 size_type
1038 size() const _GLIBCXX_NOEXCEPTnoexcept
1039 { return _M_impl._M_node_count; }
1040
1041 size_type
1042 max_size() const _GLIBCXX_NOEXCEPTnoexcept
1043 { return _Alloc_traits::max_size(_M_get_Node_allocator()); }
1044
1045 void
1046 swap(_Rb_tree& __t)
1047 _GLIBCXX_NOEXCEPT_IF(__is_nothrow_swappable<_Compare>::value)noexcept(__is_nothrow_swappable<_Compare>::value);
1048
1049 // Insert/erase.
1050#if __cplusplus201703L >= 201103L
1051 template<typename _Arg>
1052 pair<iterator, bool>
1053 _M_insert_unique(_Arg&& __x);
1054
1055 template<typename _Arg>
1056 iterator
1057 _M_insert_equal(_Arg&& __x);
1058
1059 template<typename _Arg, typename _NodeGen>
1060 iterator
1061 _M_insert_unique_(const_iterator __pos, _Arg&& __x, _NodeGen&);
1062
1063 template<typename _Arg>
1064 iterator
1065 _M_insert_unique_(const_iterator __pos, _Arg&& __x)
1066 {
1067 _Alloc_node __an(*this);
1068 return _M_insert_unique_(__pos, std::forward<_Arg>(__x), __an);
1069 }
1070
1071 template<typename _Arg, typename _NodeGen>
1072 iterator
1073 _M_insert_equal_(const_iterator __pos, _Arg&& __x, _NodeGen&);
1074
1075 template<typename _Arg>
1076 iterator
1077 _M_insert_equal_(const_iterator __pos, _Arg&& __x)
1078 {
1079 _Alloc_node __an(*this);
1080 return _M_insert_equal_(__pos, std::forward<_Arg>(__x), __an);
1081 }
1082
1083 template<typename... _Args>
1084 pair<iterator, bool>
1085 _M_emplace_unique(_Args&&... __args);
1086
1087 template<typename... _Args>
1088 iterator
1089 _M_emplace_equal(_Args&&... __args);
1090
1091 template<typename... _Args>
1092 iterator
1093 _M_emplace_hint_unique(const_iterator __pos, _Args&&... __args);
1094
1095 template<typename... _Args>
1096 iterator
1097 _M_emplace_hint_equal(const_iterator __pos, _Args&&... __args);
1098
1099 template<typename _Iter>
1100 using __same_value_type
1101 = is_same<value_type, typename iterator_traits<_Iter>::value_type>;
1102
1103 template<typename _InputIterator>
1104 __enable_if_t<__same_value_type<_InputIterator>::value>
1105 _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
1106 {
1107 _Alloc_node __an(*this);
1108 for (; __first != __last; ++__first)
1109 _M_insert_unique_(end(), *__first, __an);
1110 }
1111
1112 template<typename _InputIterator>
1113 __enable_if_t<!__same_value_type<_InputIterator>::value>
1114 _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
1115 {
1116 for (; __first != __last; ++__first)
1117 _M_emplace_unique(*__first);
1118 }
1119
1120 template<typename _InputIterator>
1121 __enable_if_t<__same_value_type<_InputIterator>::value>
1122 _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
1123 {
1124 _Alloc_node __an(*this);
1125 for (; __first != __last; ++__first)
1126 _M_insert_equal_(end(), *__first, __an);
1127 }
1128
1129 template<typename _InputIterator>
1130 __enable_if_t<!__same_value_type<_InputIterator>::value>
1131 _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
1132 {
1133 _Alloc_node __an(*this);
1134 for (; __first != __last; ++__first)
1135 _M_emplace_equal(*__first);
1136 }
1137#else
1138 pair<iterator, bool>
1139 _M_insert_unique(const value_type& __x);
1140
1141 iterator
1142 _M_insert_equal(const value_type& __x);
1143
1144 template<typename _NodeGen>
1145 iterator
1146 _M_insert_unique_(const_iterator __pos, const value_type& __x,
1147 _NodeGen&);
1148
1149 iterator
1150 _M_insert_unique_(const_iterator __pos, const value_type& __x)
1151 {
1152 _Alloc_node __an(*this);
1153 return _M_insert_unique_(__pos, __x, __an);
1154 }
1155
1156 template<typename _NodeGen>
1157 iterator
1158 _M_insert_equal_(const_iterator __pos, const value_type& __x,
1159 _NodeGen&);
1160 iterator
1161 _M_insert_equal_(const_iterator __pos, const value_type& __x)
1162 {
1163 _Alloc_node __an(*this);
1164 return _M_insert_equal_(__pos, __x, __an);
1165 }
1166
1167 template<typename _InputIterator>
1168 void
1169 _M_insert_range_unique(_InputIterator __first, _InputIterator __last)
1170 {
1171 _Alloc_node __an(*this);
1172 for (; __first != __last; ++__first)
1173 _M_insert_unique_(end(), *__first, __an);
1174 }
1175
1176 template<typename _InputIterator>
1177 void
1178 _M_insert_range_equal(_InputIterator __first, _InputIterator __last)
1179 {
1180 _Alloc_node __an(*this);
1181 for (; __first != __last; ++__first)
1182 _M_insert_equal_(end(), *__first, __an);
1183 }
1184#endif
1185
1186 private:
1187 void
1188 _M_erase_aux(const_iterator __position);
1189
1190 void
1191 _M_erase_aux(const_iterator __first, const_iterator __last);
1192
1193 public:
1194#if __cplusplus201703L >= 201103L
1195 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1196 // DR 130. Associative erase should return an iterator.
1197 _GLIBCXX_ABI_TAG_CXX11__attribute ((__abi_tag__ ("cxx11")))
1198 iterator
1199 erase(const_iterator __position)
1200 {
1201 __glibcxx_assert(__position != end());
1202 const_iterator __result = __position;
1203 ++__result;
1204 _M_erase_aux(__position);
1205 return __result._M_const_cast();
1206 }
1207
1208 // LWG 2059.
1209 _GLIBCXX_ABI_TAG_CXX11__attribute ((__abi_tag__ ("cxx11")))
1210 iterator
1211 erase(iterator __position)
1212 {
1213 __glibcxx_assert(__position != end());
1214 iterator __result = __position;
1215 ++__result;
1216 _M_erase_aux(__position);
1217 return __result;
1218 }
1219#else
1220 void
1221 erase(iterator __position)
1222 {
1223 __glibcxx_assert(__position != end());
1224 _M_erase_aux(__position);
1225 }
1226
1227 void
1228 erase(const_iterator __position)
1229 {
1230 __glibcxx_assert(__position != end());
1231 _M_erase_aux(__position);
1232 }
1233#endif
1234
1235 size_type
1236 erase(const key_type& __x);
1237
1238#if __cplusplus201703L >= 201103L
1239 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1240 // DR 130. Associative erase should return an iterator.
1241 _GLIBCXX_ABI_TAG_CXX11__attribute ((__abi_tag__ ("cxx11")))
1242 iterator
1243 erase(const_iterator __first, const_iterator __last)
1244 {
1245 _M_erase_aux(__first, __last);
1246 return __last._M_const_cast();
1247 }
1248#else
1249 void
1250 erase(iterator __first, iterator __last)
1251 { _M_erase_aux(__first, __last); }
1252
1253 void
1254 erase(const_iterator __first, const_iterator __last)
1255 { _M_erase_aux(__first, __last); }
1256#endif
1257
1258 void
1259 clear() _GLIBCXX_NOEXCEPTnoexcept
1260 {
1261 _M_erase(_M_begin());
1262 _M_impl._M_reset();
1263 }
1264
1265 // Set operations.
1266 iterator
1267 find(const key_type& __k);
1268
1269 const_iterator
1270 find(const key_type& __k) const;
1271
1272 size_type
1273 count(const key_type& __k) const;
1274
1275 iterator
1276 lower_bound(const key_type& __k)
1277 { return _M_lower_bound(_M_begin(), _M_end(), __k); }
1278
1279 const_iterator
1280 lower_bound(const key_type& __k) const
1281 { return _M_lower_bound(_M_begin(), _M_end(), __k); }
1282
1283 iterator
1284 upper_bound(const key_type& __k)
1285 { return _M_upper_bound(_M_begin(), _M_end(), __k); }
1286
1287 const_iterator
1288 upper_bound(const key_type& __k) const
1289 { return _M_upper_bound(_M_begin(), _M_end(), __k); }
1290
1291 pair<iterator, iterator>
1292 equal_range(const key_type& __k);
1293
1294 pair<const_iterator, const_iterator>
1295 equal_range(const key_type& __k) const;
1296
1297#if __cplusplus201703L >= 201402L
1298 template<typename _Kt,
1299 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1300 iterator
1301 _M_find_tr(const _Kt& __k)
1302 {
1303 const _Rb_tree* __const_this = this;
1304 return __const_this->_M_find_tr(__k)._M_const_cast();
1305 }
1306
1307 template<typename _Kt,
1308 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1309 const_iterator
1310 _M_find_tr(const _Kt& __k) const
1311 {
1312 auto __j = _M_lower_bound_tr(__k);
1313 if (__j != end() && _M_impl._M_key_compare(__k, _S_key(__j._M_node)))
1314 __j = end();
1315 return __j;
1316 }
1317
1318 template<typename _Kt,
1319 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1320 size_type
1321 _M_count_tr(const _Kt& __k) const
1322 {
1323 auto __p = _M_equal_range_tr(__k);
1324 return std::distance(__p.first, __p.second);
1325 }
1326
1327 template<typename _Kt,
1328 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1329 iterator
1330 _M_lower_bound_tr(const _Kt& __k)
1331 {
1332 const _Rb_tree* __const_this = this;
1333 return __const_this->_M_lower_bound_tr(__k)._M_const_cast();
1334 }
1335
1336 template<typename _Kt,
1337 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1338 const_iterator
1339 _M_lower_bound_tr(const _Kt& __k) const
1340 {
1341 auto __x = _M_begin();
1342 auto __y = _M_end();
1343 while (__x != 0)
1344 if (!_M_impl._M_key_compare(_S_key(__x), __k))
1345 {
1346 __y = __x;
1347 __x = _S_left(__x);
1348 }
1349 else
1350 __x = _S_right(__x);
1351 return const_iterator(__y);
1352 }
1353
1354 template<typename _Kt,
1355 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1356 iterator
1357 _M_upper_bound_tr(const _Kt& __k)
1358 {
1359 const _Rb_tree* __const_this = this;
1360 return __const_this->_M_upper_bound_tr(__k)._M_const_cast();
1361 }
1362
1363 template<typename _Kt,
1364 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1365 const_iterator
1366 _M_upper_bound_tr(const _Kt& __k) const
1367 {
1368 auto __x = _M_begin();
1369 auto __y = _M_end();
1370 while (__x != 0)
1371 if (_M_impl._M_key_compare(__k, _S_key(__x)))
1372 {
1373 __y = __x;
1374 __x = _S_left(__x);
1375 }
1376 else
1377 __x = _S_right(__x);
1378 return const_iterator(__y);
1379 }
1380
1381 template<typename _Kt,
1382 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1383 pair<iterator, iterator>
1384 _M_equal_range_tr(const _Kt& __k)
1385 {
1386 const _Rb_tree* __const_this = this;
1387 auto __ret = __const_this->_M_equal_range_tr(__k);
1388 return { __ret.first._M_const_cast(), __ret.second._M_const_cast() };
1389 }
1390
1391 template<typename _Kt,
1392 typename _Req = __has_is_transparent_t<_Compare, _Kt>>
1393 pair<const_iterator, const_iterator>
1394 _M_equal_range_tr(const _Kt& __k) const
1395 {
1396 auto __low = _M_lower_bound_tr(__k);
1397 auto __high = __low;
1398 auto& __cmp = _M_impl._M_key_compare;
1399 while (__high != end() && !__cmp(__k, _S_key(__high._M_node)))
1400 ++__high;
1401 return { __low, __high };
1402 }
1403#endif
1404
1405 // Debugging.
1406 bool
1407 __rb_verify() const;
1408
1409#if __cplusplus201703L >= 201103L
1410 _Rb_tree&
1411 operator=(_Rb_tree&&)
1412 noexcept(_Alloc_traits::_S_nothrow_move()
1413 && is_nothrow_move_assignable<_Compare>::value);
1414
1415 template<typename _Iterator>
1416 void
1417 _M_assign_unique(_Iterator, _Iterator);
1418
1419 template<typename _Iterator>
1420 void
1421 _M_assign_equal(_Iterator, _Iterator);
1422
1423 private:
1424 // Move elements from container with equal allocator.
1425 void
1426 _M_move_data(_Rb_tree& __x, true_type)
1427 { _M_impl._M_move_data(__x._M_impl); }
1428
1429 // Move elements from container with possibly non-equal allocator,
1430 // which might result in a copy not a move.
1431 void
1432 _M_move_data(_Rb_tree&, false_type);
1433
1434 // Move assignment from container with equal allocator.
1435 void
1436 _M_move_assign(_Rb_tree&, true_type);
1437
1438 // Move assignment from container with possibly non-equal allocator,
1439 // which might result in a copy not a move.
1440 void
1441 _M_move_assign(_Rb_tree&, false_type);
1442#endif
1443
1444#if __cplusplus201703L > 201402L
1445 public:
1446 /// Re-insert an extracted node.
1447 insert_return_type
1448 _M_reinsert_node_unique(node_type&& __nh)
1449 {
1450 insert_return_type __ret;
1451 if (__nh.empty())
1452 __ret.position = end();
1453 else
1454 {
1455 __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
1456
1457 auto __res = _M_get_insert_unique_pos(__nh._M_key());
1458 if (__res.second)
1459 {
1460 __ret.position
1461 = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
1462 __nh._M_ptr = nullptr;
1463 __ret.inserted = true;
1464 }
1465 else
1466 {
1467 __ret.node = std::move(__nh);
1468 __ret.position = iterator(__res.first);
1469 __ret.inserted = false;
1470 }
1471 }
1472 return __ret;
1473 }
1474
1475 /// Re-insert an extracted node.
1476 iterator
1477 _M_reinsert_node_equal(node_type&& __nh)
1478 {
1479 iterator __ret;
1480 if (__nh.empty())
1481 __ret = end();
1482 else
1483 {
1484 __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
1485 auto __res = _M_get_insert_equal_pos(__nh._M_key());
1486 if (__res.second)
1487 __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
1488 else
1489 __ret = _M_insert_equal_lower_node(__nh._M_ptr);
1490 __nh._M_ptr = nullptr;
1491 }
1492 return __ret;
1493 }
1494
1495 /// Re-insert an extracted node.
1496 iterator
1497 _M_reinsert_node_hint_unique(const_iterator __hint, node_type&& __nh)
1498 {
1499 iterator __ret;
1500 if (__nh.empty())
1501 __ret = end();
1502 else
1503 {
1504 __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
1505 auto __res = _M_get_insert_hint_unique_pos(__hint, __nh._M_key());
1506 if (__res.second)
1507 {
1508 __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
1509 __nh._M_ptr = nullptr;
1510 }
1511 else
1512 __ret = iterator(__res.first);
1513 }
1514 return __ret;
1515 }
1516
1517 /// Re-insert an extracted node.
1518 iterator
1519 _M_reinsert_node_hint_equal(const_iterator __hint, node_type&& __nh)
1520 {
1521 iterator __ret;
1522 if (__nh.empty())
1523 __ret = end();
1524 else
1525 {
1526 __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc);
1527 auto __res = _M_get_insert_hint_equal_pos(__hint, __nh._M_key());
1528 if (__res.second)
1529 __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr);
1530 else
1531 __ret = _M_insert_equal_lower_node(__nh._M_ptr);
1532 __nh._M_ptr = nullptr;
1533 }
1534 return __ret;
1535 }
1536
1537 /// Extract a node.
1538 node_type
1539 extract(const_iterator __pos)
1540 {
1541 auto __ptr = _Rb_tree_rebalance_for_erase(
1542 __pos._M_const_cast()._M_node, _M_impl._M_header);
1543 --_M_impl._M_node_count;
1544 return { static_cast<_Link_type>(__ptr), _M_get_Node_allocator() };
1545 }
1546
1547 /// Extract a node.
1548 node_type
1549 extract(const key_type& __k)
1550 {
1551 node_type __nh;
1552 auto __pos = find(__k);
1553 if (__pos != end())
1554 __nh = extract(const_iterator(__pos));
1555 return __nh;
1556 }
1557
1558 template<typename _Compare2>
1559 using _Compatible_tree
1560 = _Rb_tree<_Key, _Val, _KeyOfValue, _Compare2, _Alloc>;
1561
1562 template<typename, typename>
1563 friend class _Rb_tree_merge_helper;
1564
1565 /// Merge from a compatible container into one with unique keys.
1566 template<typename _Compare2>
1567 void
1568 _M_merge_unique(_Compatible_tree<_Compare2>& __src) noexcept
1569 {
1570 using _Merge_helper = _Rb_tree_merge_helper<_Rb_tree, _Compare2>;
1571 for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
1572 {
1573 auto __pos = __i++;
1574 auto __res = _M_get_insert_unique_pos(_KeyOfValue()(*__pos));
1575 if (__res.second)
1576 {
1577 auto& __src_impl = _Merge_helper::_S_get_impl(__src);
1578 auto __ptr = _Rb_tree_rebalance_for_erase(
1579 __pos._M_node, __src_impl._M_header);
1580 --__src_impl._M_node_count;
1581 _M_insert_node(__res.first, __res.second,
1582 static_cast<_Link_type>(__ptr));
1583 }
1584 }
1585 }
1586
1587 /// Merge from a compatible container into one with equivalent keys.
1588 template<typename _Compare2>
1589 void
1590 _M_merge_equal(_Compatible_tree<_Compare2>& __src) noexcept
1591 {
1592 using _Merge_helper = _Rb_tree_merge_helper<_Rb_tree, _Compare2>;
1593 for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
1594 {
1595 auto __pos = __i++;
1596 auto __res = _M_get_insert_equal_pos(_KeyOfValue()(*__pos));
1597 if (__res.second)
1598 {
1599 auto& __src_impl = _Merge_helper::_S_get_impl(__src);
1600 auto __ptr = _Rb_tree_rebalance_for_erase(
1601 __pos._M_node, __src_impl._M_header);
1602 --__src_impl._M_node_count;
1603 _M_insert_node(__res.first, __res.second,
1604 static_cast<_Link_type>(__ptr));
1605 }
1606 }
1607 }
1608#endif // C++17
1609
1610 friend bool
1611 operator==(const _Rb_tree& __x, const _Rb_tree& __y)
1612 {
1613 return __x.size() == __y.size()
1614 && std::equal(__x.begin(), __x.end(), __y.begin());
1615 }
1616
1617#if __cpp_lib_three_way_comparison
1618 friend auto
1619 operator<=>(const _Rb_tree& __x, const _Rb_tree& __y)
1620 {
1621 if constexpr (requires { typename __detail::__synth3way_t<_Val>; })
1622 return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
1623 __y.begin(), __y.end(),
1624 __detail::__synth3way);
1625 }
1626#else
1627 friend bool
1628 operator<(const _Rb_tree& __x, const _Rb_tree& __y)
1629 {
1630 return std::lexicographical_compare(__x.begin(), __x.end(),
1631 __y.begin(), __y.end());
1632 }
1633
1634 friend bool _GLIBCXX_DEPRECATED__attribute__ ((__deprecated__))
1635 operator!=(const _Rb_tree& __x, const _Rb_tree& __y)
1636 { return !(__x == __y); }
1637
1638 friend bool _GLIBCXX_DEPRECATED__attribute__ ((__deprecated__))
1639 operator>(const _Rb_tree& __x, const _Rb_tree& __y)
1640 { return __y < __x; }
1641
1642 friend bool _GLIBCXX_DEPRECATED__attribute__ ((__deprecated__))
1643 operator<=(const _Rb_tree& __x, const _Rb_tree& __y)
1644 { return !(__y < __x); }
1645
1646 friend bool _GLIBCXX_DEPRECATED__attribute__ ((__deprecated__))
1647 operator>=(const _Rb_tree& __x, const _Rb_tree& __y)
1648 { return !(__x < __y); }
1649#endif
1650 };
1651
1652 template<typename _Key, typename _Val, typename _KeyOfValue,
1653 typename _Compare, typename _Alloc>
1654 inline void
1655 swap(_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,
1656 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __y)
1657 { __x.swap(__y); }
1658
1659#if __cplusplus201703L >= 201103L
1660 template<typename _Key, typename _Val, typename _KeyOfValue,
1661 typename _Compare, typename _Alloc>
1662 void
1663 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1664 _M_move_data(_Rb_tree& __x, false_type)
1665 {
1666 if (_M_get_Node_allocator() == __x._M_get_Node_allocator())
1667 _M_move_data(__x, true_type());
1668 else
1669 {
1670 _Alloc_node __an(*this);
1671 auto __lbd =
1672 [&__an](const value_type& __cval)
1673 {
1674 auto& __val = const_cast<value_type&>(__cval);
1675 return __an(std::move_if_noexcept(__val));
1676 };
1677 _M_root() = _M_copy(__x, __lbd);
1678 }
1679 }
1680
1681 template<typename _Key, typename _Val, typename _KeyOfValue,
1682 typename _Compare, typename _Alloc>
1683 inline void
1684 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1685 _M_move_assign(_Rb_tree& __x, true_type)
1686 {
1687 clear();
1688 if (__x._M_root() != nullptr)
1689 _M_move_data(__x, true_type());
1690 std::__alloc_on_move(_M_get_Node_allocator(),
1691 __x._M_get_Node_allocator());
1692 }
1693
1694 template<typename _Key, typename _Val, typename _KeyOfValue,
1695 typename _Compare, typename _Alloc>
1696 void
1697 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1698 _M_move_assign(_Rb_tree& __x, false_type)
1699 {
1700 if (_M_get_Node_allocator() == __x._M_get_Node_allocator())
1701 return _M_move_assign(__x, true_type{});
1702
1703 // Try to move each node reusing existing nodes and copying __x nodes
1704 // structure.
1705 _Reuse_or_alloc_node __roan(*this);
1706 _M_impl._M_reset();
1707 if (__x._M_root() != nullptr)
1708 {
1709 auto __lbd =
1710 [&__roan](const value_type& __cval)
1711 {
1712 auto& __val = const_cast<value_type&>(__cval);
1713 return __roan(std::move(__val));
1714 };
1715 _M_root() = _M_copy(__x, __lbd);
1716 __x.clear();
1717 }
1718 }
1719
1720 template<typename _Key, typename _Val, typename _KeyOfValue,
1721 typename _Compare, typename _Alloc>
1722 inline _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
1723 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1724 operator=(_Rb_tree&& __x)
1725 noexcept(_Alloc_traits::_S_nothrow_move()
1726 && is_nothrow_move_assignable<_Compare>::value)
1727 {
1728 _M_impl._M_key_compare = std::move(__x._M_impl._M_key_compare);
1729 _M_move_assign(__x, __bool_constant<_Alloc_traits::_S_nothrow_move()>());
1730 return *this;
1731 }
1732
1733 template<typename _Key, typename _Val, typename _KeyOfValue,
1734 typename _Compare, typename _Alloc>
1735 template<typename _Iterator>
1736 void
1737 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1738 _M_assign_unique(_Iterator __first, _Iterator __last)
1739 {
1740 _Reuse_or_alloc_node __roan(*this);
1741 _M_impl._M_reset();
1742 for (; __first != __last; ++__first)
1743 _M_insert_unique_(end(), *__first, __roan);
1744 }
1745
1746 template<typename _Key, typename _Val, typename _KeyOfValue,
1747 typename _Compare, typename _Alloc>
1748 template<typename _Iterator>
1749 void
1750 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1751 _M_assign_equal(_Iterator __first, _Iterator __last)
1752 {
1753 _Reuse_or_alloc_node __roan(*this);
1754 _M_impl._M_reset();
1755 for (; __first != __last; ++__first)
1756 _M_insert_equal_(end(), *__first, __roan);
1757 }
1758#endif
1759
1760 template<typename _Key, typename _Val, typename _KeyOfValue,
1761 typename _Compare, typename _Alloc>
1762 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
1763 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1764 operator=(const _Rb_tree& __x)
1765 {
1766 if (this != &__x)
1767 {
1768 // Note that _Key may be a constant type.
1769#if __cplusplus201703L >= 201103L
1770 if (_Alloc_traits::_S_propagate_on_copy_assign())
1771 {
1772 auto& __this_alloc = this->_M_get_Node_allocator();
1773 auto& __that_alloc = __x._M_get_Node_allocator();
1774 if (!_Alloc_traits::_S_always_equal()
1775 && __this_alloc != __that_alloc)
1776 {
1777 // Replacement allocator cannot free existing storage, we need
1778 // to erase nodes first.
1779 clear();
1780 std::__alloc_on_copy(__this_alloc, __that_alloc);
1781 }
1782 }
1783#endif
1784
1785 _Reuse_or_alloc_node __roan(*this);
1786 _M_impl._M_reset();
1787 _M_impl._M_key_compare = __x._M_impl._M_key_compare;
1788 if (__x._M_root() != 0)
1789 _M_root() = _M_copy(__x, __roan);
1790 }
1791
1792 return *this;
1793 }
1794
1795 template<typename _Key, typename _Val, typename _KeyOfValue,
1796 typename _Compare, typename _Alloc>
1797#if __cplusplus201703L >= 201103L
1798 template<typename _Arg, typename _NodeGen>
1799#else
1800 template<typename _NodeGen>
1801#endif
1802 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
1803 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1804 _M_insert_(_Base_ptr __x, _Base_ptr __p,
1805#if __cplusplus201703L >= 201103L
1806 _Arg&& __v,
1807#else
1808 const _Val& __v,
1809#endif
1810 _NodeGen& __node_gen)
1811 {
1812 bool __insert_left = (__x != 0 || __p == _M_end()
1813 || _M_impl._M_key_compare(_KeyOfValue()(__v),
1814 _S_key(__p)));
1815
1816 _Link_type __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v));
1817
1818 _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
1819 this->_M_impl._M_header);
1820 ++_M_impl._M_node_count;
1821 return iterator(__z);
1822 }
1823
1824 template<typename _Key, typename _Val, typename _KeyOfValue,
1825 typename _Compare, typename _Alloc>
1826#if __cplusplus201703L >= 201103L
1827 template<typename _Arg>
1828#endif
1829 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
1830 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1831#if __cplusplus201703L >= 201103L
1832 _M_insert_lower(_Base_ptr __p, _Arg&& __v)
1833#else
1834 _M_insert_lower(_Base_ptr __p, const _Val& __v)
1835#endif
1836 {
1837 bool __insert_left = (__p == _M_end()
1838 || !_M_impl._M_key_compare(_S_key(__p),
1839 _KeyOfValue()(__v)));
1840
1841 _Link_type __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v));
1842
1843 _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
1844 this->_M_impl._M_header);
1845 ++_M_impl._M_node_count;
1846 return iterator(__z);
1847 }
1848
1849 template<typename _Key, typename _Val, typename _KeyOfValue,
1850 typename _Compare, typename _Alloc>
1851#if __cplusplus201703L >= 201103L
1852 template<typename _Arg>
1853#endif
1854 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
1855 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1856#if __cplusplus201703L >= 201103L
1857 _M_insert_equal_lower(_Arg&& __v)
1858#else
1859 _M_insert_equal_lower(const _Val& __v)
1860#endif
1861 {
1862 _Link_type __x = _M_begin();
1863 _Base_ptr __y = _M_end();
1864 while (__x != 0)
1865 {
1866 __y = __x;
1867 __x = !_M_impl._M_key_compare(_S_key(__x), _KeyOfValue()(__v)) ?
1868 _S_left(__x) : _S_right(__x);
1869 }
1870 return _M_insert_lower(__y, _GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v));
1871 }
1872
1873 template<typename _Key, typename _Val, typename _KoV,
1874 typename _Compare, typename _Alloc>
1875 template<typename _NodeGen>
1876 typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type
1877 _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::
1878 _M_copy(_Const_Link_type __x, _Base_ptr __p, _NodeGen& __node_gen)
1879 {
1880 // Structural copy. __x and __p must be non-null.
1881 _Link_type __top = _M_clone_node(__x, __node_gen);
1882 __top->_M_parent = __p;
1883
1884 __trytry
1885 {
1886 if (__x->_M_right)
1887 __top->_M_right = _M_copy(_S_right(__x), __top, __node_gen);
1888 __p = __top;
1889 __x = _S_left(__x);
1890
1891 while (__x != 0)
1892 {
1893 _Link_type __y = _M_clone_node(__x, __node_gen);
1894 __p->_M_left = __y;
1895 __y->_M_parent = __p;
1896 if (__x->_M_right)
1897 __y->_M_right = _M_copy(_S_right(__x), __y, __node_gen);
1898 __p = __y;
1899 __x = _S_left(__x);
1900 }
1901 }
1902 __catch(...)catch(...)
1903 {
1904 _M_erase(__top);
1905 __throw_exception_againthrow;
1906 }
1907 return __top;
1908 }
1909
1910 template<typename _Key, typename _Val, typename _KeyOfValue,
1911 typename _Compare, typename _Alloc>
1912 void
1913 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1914 _M_erase(_Link_type __x)
1915 {
1916 // Erase without rebalancing.
1917 while (__x != 0)
1918 {
1919 _M_erase(_S_right(__x));
1920 _Link_type __y = _S_left(__x);
1921 _M_drop_node(__x);
1922 __x = __y;
1923 }
1924 }
1925
1926 template<typename _Key, typename _Val, typename _KeyOfValue,
1927 typename _Compare, typename _Alloc>
1928 typename _Rb_tree<_Key, _Val, _KeyOfValue,
1929 _Compare, _Alloc>::iterator
1930 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1931 _M_lower_bound(_Link_type __x, _Base_ptr __y,
1932 const _Key& __k)
1933 {
1934 while (__x != 0)
1935 if (!_M_impl._M_key_compare(_S_key(__x), __k))
1936 __y = __x, __x = _S_left(__x);
1937 else
1938 __x = _S_right(__x);
1939 return iterator(__y);
1940 }
1941
1942 template<typename _Key, typename _Val, typename _KeyOfValue,
1943 typename _Compare, typename _Alloc>
1944 typename _Rb_tree<_Key, _Val, _KeyOfValue,
1945 _Compare, _Alloc>::const_iterator
1946 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1947 _M_lower_bound(_Const_Link_type __x, _Const_Base_ptr __y,
1948 const _Key& __k) const
1949 {
1950 while (__x != 0)
1951 if (!_M_impl._M_key_compare(_S_key(__x), __k))
1952 __y = __x, __x = _S_left(__x);
1953 else
1954 __x = _S_right(__x);
1955 return const_iterator(__y);
1956 }
1957
1958 template<typename _Key, typename _Val, typename _KeyOfValue,
1959 typename _Compare, typename _Alloc>
1960 typename _Rb_tree<_Key, _Val, _KeyOfValue,
1961 _Compare, _Alloc>::iterator
1962 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1963 _M_upper_bound(_Link_type __x, _Base_ptr __y,
1964 const _Key& __k)
1965 {
1966 while (__x != 0)
1967 if (_M_impl._M_key_compare(__k, _S_key(__x)))
1968 __y = __x, __x = _S_left(__x);
1969 else
1970 __x = _S_right(__x);
1971 return iterator(__y);
1972 }
1973
1974 template<typename _Key, typename _Val, typename _KeyOfValue,
1975 typename _Compare, typename _Alloc>
1976 typename _Rb_tree<_Key, _Val, _KeyOfValue,
1977 _Compare, _Alloc>::const_iterator
1978 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1979 _M_upper_bound(_Const_Link_type __x, _Const_Base_ptr __y,
1980 const _Key& __k) const
1981 {
1982 while (__x != 0)
1983 if (_M_impl._M_key_compare(__k, _S_key(__x)))
1984 __y = __x, __x = _S_left(__x);
1985 else
1986 __x = _S_right(__x);
1987 return const_iterator(__y);
1988 }
1989
1990 template<typename _Key, typename _Val, typename _KeyOfValue,
1991 typename _Compare, typename _Alloc>
1992 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
1993 _Compare, _Alloc>::iterator,
1994 typename _Rb_tree<_Key, _Val, _KeyOfValue,
1995 _Compare, _Alloc>::iterator>
1996 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
1997 equal_range(const _Key& __k)
1998 {
1999 _Link_type __x = _M_begin();
2000 _Base_ptr __y = _M_end();
2001 while (__x != 0)
2002 {
2003 if (_M_impl._M_key_compare(_S_key(__x), __k))
2004 __x = _S_right(__x);
2005 else if (_M_impl._M_key_compare(__k, _S_key(__x)))
2006 __y = __x, __x = _S_left(__x);
2007 else
2008 {
2009 _Link_type __xu(__x);
2010 _Base_ptr __yu(__y);
2011 __y = __x, __x = _S_left(__x);
2012 __xu = _S_right(__xu);
2013 return pair<iterator,
2014 iterator>(_M_lower_bound(__x, __y, __k),
2015 _M_upper_bound(__xu, __yu, __k));
2016 }
2017 }
2018 return pair<iterator, iterator>(iterator(__y),
2019 iterator(__y));
2020 }
2021
2022 template<typename _Key, typename _Val, typename _KeyOfValue,
2023 typename _Compare, typename _Alloc>
2024 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2025 _Compare, _Alloc>::const_iterator,
2026 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2027 _Compare, _Alloc>::const_iterator>
2028 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2029 equal_range(const _Key& __k) const
2030 {
2031 _Const_Link_type __x = _M_begin();
2032 _Const_Base_ptr __y = _M_end();
2033 while (__x != 0)
2034 {
2035 if (_M_impl._M_key_compare(_S_key(__x), __k))
2036 __x = _S_right(__x);
2037 else if (_M_impl._M_key_compare(__k, _S_key(__x)))
2038 __y = __x, __x = _S_left(__x);
2039 else
2040 {
2041 _Const_Link_type __xu(__x);
2042 _Const_Base_ptr __yu(__y);
2043 __y = __x, __x = _S_left(__x);
2044 __xu = _S_right(__xu);
2045 return pair<const_iterator,
2046 const_iterator>(_M_lower_bound(__x, __y, __k),
2047 _M_upper_bound(__xu, __yu, __k));
2048 }
2049 }
2050 return pair<const_iterator, const_iterator>(const_iterator(__y),
2051 const_iterator(__y));
2052 }
2053
2054 template<typename _Key, typename _Val, typename _KeyOfValue,
2055 typename _Compare, typename _Alloc>
2056 void
2057 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2058 swap(_Rb_tree& __t)
2059 _GLIBCXX_NOEXCEPT_IF(__is_nothrow_swappable<_Compare>::value)noexcept(__is_nothrow_swappable<_Compare>::value)
2060 {
2061 if (_M_root() == 0)
2062 {
2063 if (__t._M_root() != 0)
2064 _M_impl._M_move_data(__t._M_impl);
2065 }
2066 else if (__t._M_root() == 0)
2067 __t._M_impl._M_move_data(_M_impl);
2068 else
2069 {
2070 std::swap(_M_root(),__t._M_root());
2071 std::swap(_M_leftmost(),__t._M_leftmost());
2072 std::swap(_M_rightmost(),__t._M_rightmost());
2073
2074 _M_root()->_M_parent = _M_end();
2075 __t._M_root()->_M_parent = __t._M_end();
2076 std::swap(this->_M_impl._M_node_count, __t._M_impl._M_node_count);
2077 }
2078 // No need to swap header's color as it does not change.
2079 std::swap(this->_M_impl._M_key_compare, __t._M_impl._M_key_compare);
2080
2081 _Alloc_traits::_S_on_swap(_M_get_Node_allocator(),
2082 __t._M_get_Node_allocator());
2083 }
2084
2085 template<typename _Key, typename _Val, typename _KeyOfValue,
2086 typename _Compare, typename _Alloc>
2087 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2088 _Compare, _Alloc>::_Base_ptr,
2089 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2090 _Compare, _Alloc>::_Base_ptr>
2091 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2092 _M_get_insert_unique_pos(const key_type& __k)
2093 {
2094 typedef pair<_Base_ptr, _Base_ptr> _Res;
2095 _Link_type __x = _M_begin();
2096 _Base_ptr __y = _M_end();
2097 bool __comp = true;
2098 while (__x != 0)
2099 {
2100 __y = __x;
2101 __comp = _M_impl._M_key_compare(__k, _S_key(__x));
2102 __x = __comp ? _S_left(__x) : _S_right(__x);
2103 }
2104 iterator __j = iterator(__y);
2105 if (__comp)
2106 {
2107 if (__j == begin())
2108 return _Res(__x, __y);
2109 else
2110 --__j;
2111 }
2112 if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
2113 return _Res(__x, __y);
2114 return _Res(__j._M_node, 0);
2115 }
2116
2117 template<typename _Key, typename _Val, typename _KeyOfValue,
2118 typename _Compare, typename _Alloc>
2119 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2120 _Compare, _Alloc>::_Base_ptr,
2121 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2122 _Compare, _Alloc>::_Base_ptr>
2123 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2124 _M_get_insert_equal_pos(const key_type& __k)
2125 {
2126 typedef pair<_Base_ptr, _Base_ptr> _Res;
2127 _Link_type __x = _M_begin();
2128 _Base_ptr __y = _M_end();
2129 while (__x != 0)
2130 {
2131 __y = __x;
2132 __x = _M_impl._M_key_compare(__k, _S_key(__x)) ?
2133 _S_left(__x) : _S_right(__x);
2134 }
2135 return _Res(__x, __y);
2136 }
2137
2138 template<typename _Key, typename _Val, typename _KeyOfValue,
2139 typename _Compare, typename _Alloc>
2140#if __cplusplus201703L >= 201103L
2141 template<typename _Arg>
2142#endif
2143 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2144 _Compare, _Alloc>::iterator, bool>
2145 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2146#if __cplusplus201703L >= 201103L
2147 _M_insert_unique(_Arg&& __v)
2148#else
2149 _M_insert_unique(const _Val& __v)
2150#endif
2151 {
2152 typedef pair<iterator, bool> _Res;
2153 pair<_Base_ptr, _Base_ptr> __res
2154 = _M_get_insert_unique_pos(_KeyOfValue()(__v));
2155
2156 if (__res.second)
2157 {
2158 _Alloc_node __an(*this);
2159 return _Res(_M_insert_(__res.first, __res.second,
2160 _GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v), __an),
2161 true);
2162 }
2163
2164 return _Res(iterator(__res.first), false);
2165 }
2166
2167 template<typename _Key, typename _Val, typename _KeyOfValue,
2168 typename _Compare, typename _Alloc>
2169#if __cplusplus201703L >= 201103L
2170 template<typename _Arg>
2171#endif
2172 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2173 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2174#if __cplusplus201703L >= 201103L
2175 _M_insert_equal(_Arg&& __v)
2176#else
2177 _M_insert_equal(const _Val& __v)
2178#endif
2179 {
2180 pair<_Base_ptr, _Base_ptr> __res
2181 = _M_get_insert_equal_pos(_KeyOfValue()(__v));
2182 _Alloc_node __an(*this);
2183 return _M_insert_(__res.first, __res.second,
2184 _GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v), __an);
2185 }
2186
2187 template<typename _Key, typename _Val, typename _KeyOfValue,
2188 typename _Compare, typename _Alloc>
2189 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2190 _Compare, _Alloc>::_Base_ptr,
2191 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2192 _Compare, _Alloc>::_Base_ptr>
2193 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2194 _M_get_insert_hint_unique_pos(const_iterator __position,
2195 const key_type& __k)
2196 {
2197 iterator __pos = __position._M_const_cast();
2198 typedef pair<_Base_ptr, _Base_ptr> _Res;
2199
2200 // end()
2201 if (__pos._M_node == _M_end())
2202 {
2203 if (size() > 0
2204 && _M_impl._M_key_compare(_S_key(_M_rightmost()), __k))
2205 return _Res(0, _M_rightmost());
2206 else
2207 return _M_get_insert_unique_pos(__k);
2208 }
2209 else if (_M_impl._M_key_compare(__k, _S_key(__pos._M_node)))
2210 {
2211 // First, try before...
2212 iterator __before = __pos;
2213 if (__pos._M_node == _M_leftmost()) // begin()
2214 return _Res(_M_leftmost(), _M_leftmost());
2215 else if (_M_impl._M_key_compare(_S_key((--__before)._M_node), __k))
2216 {
2217 if (_S_right(__before._M_node) == 0)
2218 return _Res(0, __before._M_node);
2219 else
2220 return _Res(__pos._M_node, __pos._M_node);
2221 }
2222 else
2223 return _M_get_insert_unique_pos(__k);
2224 }
2225 else if (_M_impl._M_key_compare(_S_key(__pos._M_node), __k))
2226 {
2227 // ... then try after.
2228 iterator __after = __pos;
2229 if (__pos._M_node == _M_rightmost())
2230 return _Res(0, _M_rightmost());
2231 else if (_M_impl._M_key_compare(__k, _S_key((++__after)._M_node)))
2232 {
2233 if (_S_right(__pos._M_node) == 0)
2234 return _Res(0, __pos._M_node);
2235 else
2236 return _Res(__after._M_node, __after._M_node);
2237 }
2238 else
2239 return _M_get_insert_unique_pos(__k);
2240 }
2241 else
2242 // Equivalent keys.
2243 return _Res(__pos._M_node, 0);
2244 }
2245
2246 template<typename _Key, typename _Val, typename _KeyOfValue,
2247 typename _Compare, typename _Alloc>
2248#if __cplusplus201703L >= 201103L
2249 template<typename _Arg, typename _NodeGen>
2250#else
2251 template<typename _NodeGen>
2252#endif
2253 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2254 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2255 _M_insert_unique_(const_iterator __position,
2256#if __cplusplus201703L >= 201103L
2257 _Arg&& __v,
2258#else
2259 const _Val& __v,
2260#endif
2261 _NodeGen& __node_gen)
2262 {
2263 pair<_Base_ptr, _Base_ptr> __res
2264 = _M_get_insert_hint_unique_pos(__position, _KeyOfValue()(__v));
2265
2266 if (__res.second)
2267 return _M_insert_(__res.first, __res.second,
2268 _GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v),
2269 __node_gen);
2270 return iterator(__res.first);
2271 }
2272
2273 template<typename _Key, typename _Val, typename _KeyOfValue,
2274 typename _Compare, typename _Alloc>
2275 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2276 _Compare, _Alloc>::_Base_ptr,
2277 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2278 _Compare, _Alloc>::_Base_ptr>
2279 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2280 _M_get_insert_hint_equal_pos(const_iterator __position, const key_type& __k)
2281 {
2282 iterator __pos = __position._M_const_cast();
2283 typedef pair<_Base_ptr, _Base_ptr> _Res;
2284
2285 // end()
2286 if (__pos._M_node == _M_end())
2287 {
2288 if (size() > 0
2289 && !_M_impl._M_key_compare(__k, _S_key(_M_rightmost())))
2290 return _Res(0, _M_rightmost());
2291 else
2292 return _M_get_insert_equal_pos(__k);
2293 }
2294 else if (!_M_impl._M_key_compare(_S_key(__pos._M_node), __k))
2295 {
2296 // First, try before...
2297 iterator __before = __pos;
2298 if (__pos._M_node == _M_leftmost()) // begin()
2299 return _Res(_M_leftmost(), _M_leftmost());
2300 else if (!_M_impl._M_key_compare(__k, _S_key((--__before)._M_node)))
2301 {
2302 if (_S_right(__before._M_node) == 0)
2303 return _Res(0, __before._M_node);
2304 else
2305 return _Res(__pos._M_node, __pos._M_node);
2306 }
2307 else
2308 return _M_get_insert_equal_pos(__k);
2309 }
2310 else
2311 {
2312 // ... then try after.
2313 iterator __after = __pos;
2314 if (__pos._M_node == _M_rightmost())
2315 return _Res(0, _M_rightmost());
2316 else if (!_M_impl._M_key_compare(_S_key((++__after)._M_node), __k))
2317 {
2318 if (_S_right(__pos._M_node) == 0)
2319 return _Res(0, __pos._M_node);
2320 else
2321 return _Res(__after._M_node, __after._M_node);
2322 }
2323 else
2324 return _Res(0, 0);
2325 }
2326 }
2327
2328 template<typename _Key, typename _Val, typename _KeyOfValue,
2329 typename _Compare, typename _Alloc>
2330#if __cplusplus201703L >= 201103L
2331 template<typename _Arg, typename _NodeGen>
2332#else
2333 template<typename _NodeGen>
2334#endif
2335 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2336 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2337 _M_insert_equal_(const_iterator __position,
2338#if __cplusplus201703L >= 201103L
2339 _Arg&& __v,
2340#else
2341 const _Val& __v,
2342#endif
2343 _NodeGen& __node_gen)
2344 {
2345 pair<_Base_ptr, _Base_ptr> __res
2346 = _M_get_insert_hint_equal_pos(__position, _KeyOfValue()(__v));
2347
2348 if (__res.second)
2349 return _M_insert_(__res.first, __res.second,
2350 _GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v),
2351 __node_gen);
2352
2353 return _M_insert_equal_lower(_GLIBCXX_FORWARD(_Arg, __v)std::forward<_Arg>(__v));
2354 }
2355
2356#if __cplusplus201703L >= 201103L
2357 template<typename _Key, typename _Val, typename _KeyOfValue,
2358 typename _Compare, typename _Alloc>
2359 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2360 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2361 _M_insert_node(_Base_ptr __x, _Base_ptr __p, _Link_type __z)
2362 {
2363 bool __insert_left = (__x != 0 || __p == _M_end()
2364 || _M_impl._M_key_compare(_S_key(__z),
2365 _S_key(__p)));
2366
2367 _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
2368 this->_M_impl._M_header);
2369 ++_M_impl._M_node_count;
2370 return iterator(__z);
2371 }
2372
2373 template<typename _Key, typename _Val, typename _KeyOfValue,
2374 typename _Compare, typename _Alloc>
2375 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2376 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2377 _M_insert_lower_node(_Base_ptr __p, _Link_type __z)
2378 {
2379 bool __insert_left = (__p == _M_end()
2380 || !_M_impl._M_key_compare(_S_key(__p),
2381 _S_key(__z)));
2382
2383 _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
2384 this->_M_impl._M_header);
2385 ++_M_impl._M_node_count;
2386 return iterator(__z);
2387 }
2388
2389 template<typename _Key, typename _Val, typename _KeyOfValue,
2390 typename _Compare, typename _Alloc>
2391 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2392 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2393 _M_insert_equal_lower_node(_Link_type __z)
2394 {
2395 _Link_type __x = _M_begin();
2396 _Base_ptr __y = _M_end();
2397 while (__x != 0)
2398 {
2399 __y = __x;
2400 __x = !_M_impl._M_key_compare(_S_key(__x), _S_key(__z)) ?
2401 _S_left(__x) : _S_right(__x);
2402 }
2403 return _M_insert_lower_node(__y, __z);
2404 }
2405
2406 template<typename _Key, typename _Val, typename _KeyOfValue,
2407 typename _Compare, typename _Alloc>
2408 template<typename... _Args>
2409 pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
2410 _Compare, _Alloc>::iterator, bool>
2411 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2412 _M_emplace_unique(_Args&&... __args)
2413 {
2414 _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);
2415
2416 __trytry
2417 {
2418 typedef pair<iterator, bool> _Res;
2419 auto __res = _M_get_insert_unique_pos(_S_key(__z));
2420 if (__res.second)
2421 return _Res(_M_insert_node(__res.first, __res.second, __z), true);
2422
2423 _M_drop_node(__z);
2424 return _Res(iterator(__res.first), false);
2425 }
2426 __catch(...)catch(...)
2427 {
2428 _M_drop_node(__z);
2429 __throw_exception_againthrow;
2430 }
2431 }
2432
2433 template<typename _Key, typename _Val, typename _KeyOfValue,
2434 typename _Compare, typename _Alloc>
2435 template<typename... _Args>
2436 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2437 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2438 _M_emplace_equal(_Args&&... __args)
2439 {
2440 _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);
2441
2442 __trytry
2443 {
2444 auto __res = _M_get_insert_equal_pos(_S_key(__z));
2445 return _M_insert_node(__res.first, __res.second, __z);
2446 }
2447 __catch(...)catch(...)
2448 {
2449 _M_drop_node(__z);
2450 __throw_exception_againthrow;
2451 }
2452 }
2453
2454 template<typename _Key, typename _Val, typename _KeyOfValue,
2455 typename _Compare, typename _Alloc>
2456 template<typename... _Args>
2457 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2458 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2459 _M_emplace_hint_unique(const_iterator __pos, _Args&&... __args)
2460 {
2461 _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);
2462
2463 __trytry
2464 {
2465 auto __res = _M_get_insert_hint_unique_pos(__pos, _S_key(__z));
2466
2467 if (__res.second)
2468 return _M_insert_node(__res.first, __res.second, __z);
2469
2470 _M_drop_node(__z);
2471 return iterator(__res.first);
2472 }
2473 __catch(...)catch(...)
2474 {
2475 _M_drop_node(__z);
2476 __throw_exception_againthrow;
2477 }
2478 }
2479
2480 template<typename _Key, typename _Val, typename _KeyOfValue,
2481 typename _Compare, typename _Alloc>
2482 template<typename... _Args>
2483 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
2484 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2485 _M_emplace_hint_equal(const_iterator __pos, _Args&&... __args)
2486 {
2487 _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);
2488
2489 __trytry
2490 {
2491 auto __res = _M_get_insert_hint_equal_pos(__pos, _S_key(__z));
2492
2493 if (__res.second)
2494 return _M_insert_node(__res.first, __res.second, __z);
2495
2496 return _M_insert_equal_lower_node(__z);
2497 }
2498 __catch(...)catch(...)
2499 {
2500 _M_drop_node(__z);
2501 __throw_exception_againthrow;
2502 }
2503 }
2504#endif
2505
2506
2507 template<typename _Key, typename _Val, typename _KeyOfValue,
2508 typename _Compare, typename _Alloc>
2509 void
2510 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2511 _M_erase_aux(const_iterator __position)
2512 {
2513 _Link_type __y =
2514 static_cast<_Link_type>(_Rb_tree_rebalance_for_erase
2515 (const_cast<_Base_ptr>(__position._M_node),
2516 this->_M_impl._M_header));
2517 _M_drop_node(__y);
2518 --_M_impl._M_node_count;
2519 }
2520
2521 template<typename _Key, typename _Val, typename _KeyOfValue,
2522 typename _Compare, typename _Alloc>
2523 void
2524 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2525 _M_erase_aux(const_iterator __first, const_iterator __last)
2526 {
2527 if (__first == begin() && __last == end())
2528 clear();
2529 else
2530 while (__first != __last)
2531 _M_erase_aux(__first++);
2532 }
2533
2534 template<typename _Key, typename _Val, typename _KeyOfValue,
2535 typename _Compare, typename _Alloc>
2536 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type
2537 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2538 erase(const _Key& __x)
2539 {
2540 pair<iterator, iterator> __p = equal_range(__x);
2541 const size_type __old_size = size();
2542 _M_erase_aux(__p.first, __p.second);
2543 return __old_size - size();
2544 }
2545
2546 template<typename _Key, typename _Val, typename _KeyOfValue,
2547 typename _Compare, typename _Alloc>
2548 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2549 _Compare, _Alloc>::iterator
2550 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2551 find(const _Key& __k)
2552 {
2553 iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
2554 return (__j == end()
2555 || _M_impl._M_key_compare(__k,
2556 _S_key(__j._M_node))) ? end() : __j;
2557 }
2558
2559 template<typename _Key, typename _Val, typename _KeyOfValue,
2560 typename _Compare, typename _Alloc>
2561 typename _Rb_tree<_Key, _Val, _KeyOfValue,
2562 _Compare, _Alloc>::const_iterator
2563 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2564 find(const _Key& __k) const
2565 {
2566 const_iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
2567 return (__j == end()
2568 || _M_impl._M_key_compare(__k,
2569 _S_key(__j._M_node))) ? end() : __j;
2570 }
2571
2572 template<typename _Key, typename _Val, typename _KeyOfValue,
2573 typename _Compare, typename _Alloc>
2574 typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type
2575 _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
2576 count(const _Key& __k) const
2577 {
2578 pair<const_iterator, const_iterator> __p = equal_range(__k);
2579 const size_type __n = std::distance(__p.first, __p.second);
2580 return __n;
2581 }
2582
2583 _GLIBCXX_PURE__attribute__ ((__pure__)) unsigned int
2584 _Rb_tree_black_count(const _Rb_tree_node_base* __node,
2585 const _Rb_tree_node_base* __root) throw ();
2586
2587 template<typename _Key, typename _Val, typename _KeyOfValue,
2588 typename _Compare, typename _Alloc>
2589 bool
2590 _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::__rb_verify() const
2591 {
2592 if (_M_impl._M_node_count == 0 || begin() == end())
2593 return _M_impl._M_node_count == 0 && begin() == end()
2594 && this->_M_impl._M_header._M_left == _M_end()
2595 && this->_M_impl._M_header._M_right == _M_end();
2596
2597 unsigned int __len = _Rb_tree_black_count(_M_leftmost(), _M_root());
2598 for (const_iterator __it = begin(); __it != end(); ++__it)
2599 {
2600 _Const_Link_type __x = static_cast<_Const_Link_type>(__it._M_node);
2601 _Const_Link_type __L = _S_left(__x);
2602 _Const_Link_type __R = _S_right(__x);
2603
2604 if (__x->_M_color == _S_red)
2605 if ((__L && __L->_M_color == _S_red)
2606 || (__R && __R->_M_color == _S_red))
2607 return false;
2608
2609 if (__L && _M_impl._M_key_compare(_S_key(__x), _S_key(__L)))
2610 return false;
2611 if (__R && _M_impl._M_key_compare(_S_key(__R), _S_key(__x)))
2612 return false;
2613
2614 if (!__L && !__R && _Rb_tree_black_count(__x, _M_root()) != __len)
2615 return false;
2616 }
2617
2618 if (_M_leftmost() != _Rb_tree_node_base::_S_minimum(_M_root()))
2619 return false;
2620 if (_M_rightmost() != _Rb_tree_node_base::_S_maximum(_M_root()))
2621 return false;
2622 return true;
2623 }
2624
2625#if __cplusplus201703L > 201402L
2626 // Allow access to internals of compatible _Rb_tree specializations.
2627 template<typename _Key, typename _Val, typename _Sel, typename _Cmp1,
2628 typename _Alloc, typename _Cmp2>
2629 struct _Rb_tree_merge_helper<_Rb_tree<_Key, _Val, _Sel, _Cmp1, _Alloc>,
2630 _Cmp2>
2631 {
2632 private:
2633 friend class _Rb_tree<_Key, _Val, _Sel, _Cmp1, _Alloc>;
2634
2635 static auto&
2636 _S_get_impl(_Rb_tree<_Key, _Val, _Sel, _Cmp2, _Alloc>& __tree)
2637 { return __tree._M_impl; }
2638 };
2639#endif // C++17
2640
2641_GLIBCXX_END_NAMESPACE_VERSION
2642} // namespace
2643
2644#endif