File: | home/maarten/src/libreoffice/core/svx/source/form/navigatortree.cxx |
Warning: | line 1630, column 41 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||||||||||
2 | /* | ||||||||||||
3 | * This file is part of the LibreOffice project. | ||||||||||||
4 | * | ||||||||||||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | ||||||||||||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||||||||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||||||||
8 | * | ||||||||||||
9 | * This file incorporates work covered by the following license notice: | ||||||||||||
10 | * | ||||||||||||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | ||||||||||||
12 | * contributor license agreements. See the NOTICE file distributed | ||||||||||||
13 | * with this work for additional information regarding copyright | ||||||||||||
14 | * ownership. The ASF licenses this file to you under the Apache | ||||||||||||
15 | * License, Version 2.0 (the "License"); you may not use this file | ||||||||||||
16 | * except in compliance with the License. You may obtain a copy of | ||||||||||||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | ||||||||||||
18 | */ | ||||||||||||
19 | |||||||||||||
20 | #include <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 | |||||||||||||
59 | namespace 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) | ||||||||||||
| |||||||||||||
1234 | { | ||||||||||||
1235 | const vcl::KeyCode& rCode = rKEvt.GetKeyCode(); | ||||||||||||
1236 | |||||||||||||
1237 | // delete? | ||||||||||||
1238 | if (rCode.GetCode() == KEY_DELETE && !rCode.GetModifier()) | ||||||||||||
1239 | { | ||||||||||||
1240 | 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 ? | ||||||||||||
1567 | m_xTreeView->unselect(*m_xRootEntry); // yes -> remove root from selection | ||||||||||||
1568 | |||||||||||||
1569 | if ((nSelectedEntries == 0) || bRootSelected
| ||||||||||||
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); | ||||||||||||
1573 | |||||||||||||
1574 | // i need the FormModel later | ||||||||||||
1575 | FmFormShell* pFormShell = GetNavModel()->GetFormShell(); | ||||||||||||
1576 | if (!pFormShell) | ||||||||||||
1577 | return; | ||||||||||||
1578 | FmFormModel* pFormModel = pFormShell->GetFormModel(); | ||||||||||||
1579 | if (!pFormModel) | ||||||||||||
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; | ||||||||||||
1591 | SdrPage* pPage = pPageView
| ||||||||||||
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); | ||||||||||||
1593 | |||||||||||||
1594 | MapModelToShape aModelShapes; | ||||||||||||
1595 | if ( pPage
| ||||||||||||
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(); | ||||||||||||
1607 | it != m_arrCurrentSelection.rend(); ) | ||||||||||||
1608 | { | ||||||||||||
1609 | const std::unique_ptr<weld::TreeIter>& rIter = *it; | ||||||||||||
1610 | FmEntryData* pCurrent = reinterpret_cast<FmEntryData*>(m_xTreeView->get_id(*rIter).toInt64()); | ||||||||||||
1611 | |||||||||||||
1612 | // a form ? | ||||||||||||
1613 | bool bIsForm = dynamic_cast<const FmFormData*>( pCurrent) != nullptr; | ||||||||||||
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
| ||||||||||||
1619 | MarkViewObj(static_cast<FmFormData*>(pCurrent), true/*deep*/); | ||||||||||||
1620 | |||||||||||||
1621 | // a hidden control ? | ||||||||||||
1622 | bool bIsHidden = IsHiddenControl(pCurrent); | ||||||||||||
1623 | |||||||||||||
1624 | // keep forms and hidden controls, the rest not | ||||||||||||
1625 | if (!bIsForm
| ||||||||||||
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() ) | ||||||||||||
| |||||||||||||
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; | ||||||||||||
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: */ |
1 | // Iterators -*- C++ -*- |
2 | |
3 | // Copyright (C) 2001-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /* |
26 | * |
27 | * Copyright (c) 1994 |
28 | * Hewlett-Packard Company |
29 | * |
30 | * Permission to use, copy, modify, distribute and sell this software |
31 | * and its documentation for any purpose is hereby granted without fee, |
32 | * provided that the above copyright notice appear in all copies and |
33 | * that both that copyright notice and this permission notice appear |
34 | * in supporting documentation. Hewlett-Packard Company makes no |
35 | * representations about the suitability of this software for any |
36 | * purpose. It is provided "as is" without express or implied warranty. |
37 | * |
38 | * |
39 | * Copyright (c) 1996-1998 |
40 | * Silicon Graphics Computer Systems, Inc. |
41 | * |
42 | * Permission to use, copy, modify, distribute and sell this software |
43 | * and its documentation for any purpose is hereby granted without fee, |
44 | * provided that the above copyright notice appear in all copies and |
45 | * that both that copyright notice and this permission notice appear |
46 | * in supporting documentation. Silicon Graphics makes no |
47 | * representations about the suitability of this software for any |
48 | * purpose. It is provided "as is" without express or implied warranty. |
49 | */ |
50 | |
51 | /** @file bits/stl_iterator.h |
52 | * This is an internal header file, included by other library headers. |
53 | * Do not attempt to use it directly. @headername{iterator} |
54 | * |
55 | * This file implements reverse_iterator, back_insert_iterator, |
56 | * front_insert_iterator, insert_iterator, __normal_iterator, and their |
57 | * supporting functions and overloaded operators. |
58 | */ |
59 | |
60 | #ifndef _STL_ITERATOR_H1 |
61 | #define _STL_ITERATOR_H1 1 |
62 | |
63 | #include <bits/cpp_type_traits.h> |
64 | #include <ext/type_traits.h> |
65 | #include <bits/move.h> |
66 | #include <bits/ptr_traits.h> |
67 | |
68 | #if __cplusplus201703L >= 201103L |
69 | # include <type_traits> |
70 | #endif |
71 | |
72 | #if __cplusplus201703L > 201703L |
73 | # define __cpp_lib_array_constexpr201803L 201811L |
74 | # define __cpp_lib_constexpr_iterator 201811L |
75 | #elif __cplusplus201703L == 201703L |
76 | # define __cpp_lib_array_constexpr201803L 201803L |
77 | #endif |
78 | |
79 | #if __cplusplus201703L > 201703L |
80 | # include <compare> |
81 | # include <new> |
82 | # include <bits/iterator_concepts.h> |
83 | #endif |
84 | |
85 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
86 | { |
87 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
88 | |
89 | /** |
90 | * @addtogroup iterators |
91 | * @{ |
92 | */ |
93 | |
94 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
95 | namespace __detail |
96 | { |
97 | // Weaken iterator_category _Cat to _Limit if it is derived from that, |
98 | // otherwise use _Otherwise. |
99 | template<typename _Cat, typename _Limit, typename _Otherwise = _Cat> |
100 | using __clamp_iter_cat |
101 | = conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>; |
102 | } |
103 | #endif |
104 | |
105 | // 24.4.1 Reverse iterators |
106 | /** |
107 | * Bidirectional and random access iterators have corresponding reverse |
108 | * %iterator adaptors that iterate through the data structure in the |
109 | * opposite direction. They have the same signatures as the corresponding |
110 | * iterators. The fundamental relation between a reverse %iterator and its |
111 | * corresponding %iterator @c i is established by the identity: |
112 | * @code |
113 | * &*(reverse_iterator(i)) == &*(i - 1) |
114 | * @endcode |
115 | * |
116 | * <em>This mapping is dictated by the fact that while there is always a |
117 | * pointer past the end of an array, there might not be a valid pointer |
118 | * before the beginning of an array.</em> [24.4.1]/1,2 |
119 | * |
120 | * Reverse iterators can be tricky and surprising at first. Their |
121 | * semantics make sense, however, and the trickiness is a side effect of |
122 | * the requirement that the iterators must be safe. |
123 | */ |
124 | template<typename _Iterator> |
125 | class reverse_iterator |
126 | : public iterator<typename iterator_traits<_Iterator>::iterator_category, |
127 | typename iterator_traits<_Iterator>::value_type, |
128 | typename iterator_traits<_Iterator>::difference_type, |
129 | typename iterator_traits<_Iterator>::pointer, |
130 | typename iterator_traits<_Iterator>::reference> |
131 | { |
132 | protected: |
133 | _Iterator current; |
134 | |
135 | typedef iterator_traits<_Iterator> __traits_type; |
136 | |
137 | public: |
138 | typedef _Iterator iterator_type; |
139 | typedef typename __traits_type::difference_type difference_type; |
140 | typedef typename __traits_type::pointer pointer; |
141 | typedef typename __traits_type::reference reference; |
142 | |
143 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
144 | using iterator_concept |
145 | = conditional_t<random_access_iterator<_Iterator>, |
146 | random_access_iterator_tag, |
147 | bidirectional_iterator_tag>; |
148 | using iterator_category |
149 | = __detail::__clamp_iter_cat<typename __traits_type::iterator_category, |
150 | random_access_iterator_tag>; |
151 | #endif |
152 | |
153 | /** |
154 | * The default constructor value-initializes member @p current. |
155 | * If it is a pointer, that means it is zero-initialized. |
156 | */ |
157 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
158 | // 235 No specification of default ctor for reverse_iterator |
159 | // 1012. reverse_iterator default ctor should value initialize |
160 | _GLIBCXX17_CONSTEXPRconstexpr |
161 | reverse_iterator() : current() { } |
162 | |
163 | /** |
164 | * This %iterator will move in the opposite direction that @p x does. |
165 | */ |
166 | explicit _GLIBCXX17_CONSTEXPRconstexpr |
167 | reverse_iterator(iterator_type __x) : current(__x) { } |
168 | |
169 | /** |
170 | * The copy constructor is normal. |
171 | */ |
172 | _GLIBCXX17_CONSTEXPRconstexpr |
173 | reverse_iterator(const reverse_iterator& __x) |
174 | : current(__x.current) { } |
175 | |
176 | #if __cplusplus201703L >= 201103L |
177 | reverse_iterator& operator=(const reverse_iterator&) = default; |
178 | #endif |
179 | |
180 | /** |
181 | * A %reverse_iterator across other types can be copied if the |
182 | * underlying %iterator can be converted to the type of @c current. |
183 | */ |
184 | template<typename _Iter> |
185 | _GLIBCXX17_CONSTEXPRconstexpr |
186 | reverse_iterator(const reverse_iterator<_Iter>& __x) |
187 | : current(__x.base()) { } |
188 | |
189 | /** |
190 | * @return @c current, the %iterator used for underlying work. |
191 | */ |
192 | _GLIBCXX17_CONSTEXPRconstexpr iterator_type |
193 | base() const |
194 | { return current; } |
195 | |
196 | /** |
197 | * @return A reference to the value at @c --current |
198 | * |
199 | * This requires that @c --current is dereferenceable. |
200 | * |
201 | * @warning This implementation requires that for an iterator of the |
202 | * underlying iterator type, @c x, a reference obtained by |
203 | * @c *x remains valid after @c x has been modified or |
204 | * destroyed. This is a bug: http://gcc.gnu.org/PR51823 |
205 | */ |
206 | _GLIBCXX17_CONSTEXPRconstexpr reference |
207 | operator*() const |
208 | { |
209 | _Iterator __tmp = current; |
210 | return *--__tmp; |
211 | } |
212 | |
213 | /** |
214 | * @return A pointer to the value at @c --current |
215 | * |
216 | * This requires that @c --current is dereferenceable. |
217 | */ |
218 | _GLIBCXX17_CONSTEXPRconstexpr pointer |
219 | operator->() const |
220 | #if __cplusplus201703L > 201703L && __cpp_concepts >= 201907L |
221 | requires is_pointer_v<_Iterator> |
222 | || requires(const _Iterator __i) { __i.operator->(); } |
223 | #endif |
224 | { |
225 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
226 | // 1052. operator-> should also support smart pointers |
227 | _Iterator __tmp = current; |
228 | --__tmp; |
229 | return _S_to_pointer(__tmp); |
230 | } |
231 | |
232 | /** |
233 | * @return @c *this |
234 | * |
235 | * Decrements the underlying iterator. |
236 | */ |
237 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
238 | operator++() |
239 | { |
240 | --current; |
241 | return *this; |
242 | } |
243 | |
244 | /** |
245 | * @return The original value of @c *this |
246 | * |
247 | * Decrements the underlying iterator. |
248 | */ |
249 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
250 | operator++(int) |
251 | { |
252 | reverse_iterator __tmp = *this; |
253 | --current; |
254 | return __tmp; |
255 | } |
256 | |
257 | /** |
258 | * @return @c *this |
259 | * |
260 | * Increments the underlying iterator. |
261 | */ |
262 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
263 | operator--() |
264 | { |
265 | ++current; |
266 | return *this; |
267 | } |
268 | |
269 | /** |
270 | * @return A reverse_iterator with the previous value of @c *this |
271 | * |
272 | * Increments the underlying iterator. |
273 | */ |
274 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
275 | operator--(int) |
276 | { |
277 | reverse_iterator __tmp = *this; |
278 | ++current; |
279 | return __tmp; |
280 | } |
281 | |
282 | /** |
283 | * @return A reverse_iterator that refers to @c current - @a __n |
284 | * |
285 | * The underlying iterator must be a Random Access Iterator. |
286 | */ |
287 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
288 | operator+(difference_type __n) const |
289 | { return reverse_iterator(current - __n); } |
290 | |
291 | /** |
292 | * @return *this |
293 | * |
294 | * Moves the underlying iterator backwards @a __n steps. |
295 | * The underlying iterator must be a Random Access Iterator. |
296 | */ |
297 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
298 | operator+=(difference_type __n) |
299 | { |
300 | current -= __n; |
301 | return *this; |
302 | } |
303 | |
304 | /** |
305 | * @return A reverse_iterator that refers to @c current - @a __n |
306 | * |
307 | * The underlying iterator must be a Random Access Iterator. |
308 | */ |
309 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator |
310 | operator-(difference_type __n) const |
311 | { return reverse_iterator(current + __n); } |
312 | |
313 | /** |
314 | * @return *this |
315 | * |
316 | * Moves the underlying iterator forwards @a __n steps. |
317 | * The underlying iterator must be a Random Access Iterator. |
318 | */ |
319 | _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator& |
320 | operator-=(difference_type __n) |
321 | { |
322 | current += __n; |
323 | return *this; |
324 | } |
325 | |
326 | /** |
327 | * @return The value at @c current - @a __n - 1 |
328 | * |
329 | * The underlying iterator must be a Random Access Iterator. |
330 | */ |
331 | _GLIBCXX17_CONSTEXPRconstexpr reference |
332 | operator[](difference_type __n) const |
333 | { return *(*this + __n); } |
334 | |
335 | private: |
336 | template<typename _Tp> |
337 | static _GLIBCXX17_CONSTEXPRconstexpr _Tp* |
338 | _S_to_pointer(_Tp* __p) |
339 | { return __p; } |
340 | |
341 | template<typename _Tp> |
342 | static _GLIBCXX17_CONSTEXPRconstexpr pointer |
343 | _S_to_pointer(_Tp __t) |
344 | { return __t.operator->(); } |
345 | }; |
346 | |
347 | //@{ |
348 | /** |
349 | * @param __x A %reverse_iterator. |
350 | * @param __y A %reverse_iterator. |
351 | * @return A simple bool. |
352 | * |
353 | * Reverse iterators forward comparisons to their underlying base() |
354 | * iterators. |
355 | * |
356 | */ |
357 | #if __cplusplus201703L <= 201703L || ! defined __cpp_lib_concepts |
358 | template<typename _Iterator> |
359 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
360 | operator==(const reverse_iterator<_Iterator>& __x, |
361 | const reverse_iterator<_Iterator>& __y) |
362 | { return __x.base() == __y.base(); } |
363 | |
364 | template<typename _Iterator> |
365 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
366 | operator<(const reverse_iterator<_Iterator>& __x, |
367 | const reverse_iterator<_Iterator>& __y) |
368 | { return __y.base() < __x.base(); } |
369 | |
370 | template<typename _Iterator> |
371 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
372 | operator!=(const reverse_iterator<_Iterator>& __x, |
373 | const reverse_iterator<_Iterator>& __y) |
374 | { return !(__x == __y); } |
375 | |
376 | template<typename _Iterator> |
377 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
378 | operator>(const reverse_iterator<_Iterator>& __x, |
379 | const reverse_iterator<_Iterator>& __y) |
380 | { return __y < __x; } |
381 | |
382 | template<typename _Iterator> |
383 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
384 | operator<=(const reverse_iterator<_Iterator>& __x, |
385 | const reverse_iterator<_Iterator>& __y) |
386 | { return !(__y < __x); } |
387 | |
388 | template<typename _Iterator> |
389 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
390 | operator>=(const reverse_iterator<_Iterator>& __x, |
391 | const reverse_iterator<_Iterator>& __y) |
392 | { return !(__x < __y); } |
393 | |
394 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
395 | // DR 280. Comparison of reverse_iterator to const reverse_iterator. |
396 | template<typename _IteratorL, typename _IteratorR> |
397 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
398 | operator==(const reverse_iterator<_IteratorL>& __x, |
399 | const reverse_iterator<_IteratorR>& __y) |
400 | { return __x.base() == __y.base(); } |
401 | |
402 | template<typename _IteratorL, typename _IteratorR> |
403 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
404 | operator<(const reverse_iterator<_IteratorL>& __x, |
405 | const reverse_iterator<_IteratorR>& __y) |
406 | { return __y.base() < __x.base(); } |
407 | |
408 | template<typename _IteratorL, typename _IteratorR> |
409 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
410 | operator!=(const reverse_iterator<_IteratorL>& __x, |
411 | const reverse_iterator<_IteratorR>& __y) |
412 | { return !(__x == __y); } |
413 | |
414 | template<typename _IteratorL, typename _IteratorR> |
415 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
416 | operator>(const reverse_iterator<_IteratorL>& __x, |
417 | const reverse_iterator<_IteratorR>& __y) |
418 | { return __y < __x; } |
419 | |
420 | template<typename _IteratorL, typename _IteratorR> |
421 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
422 | operator<=(const reverse_iterator<_IteratorL>& __x, |
423 | const reverse_iterator<_IteratorR>& __y) |
424 | { return !(__y < __x); } |
425 | |
426 | template<typename _IteratorL, typename _IteratorR> |
427 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
428 | operator>=(const reverse_iterator<_IteratorL>& __x, |
429 | const reverse_iterator<_IteratorR>& __y) |
430 | { return !(__x < __y); } |
431 | #else // C++20 |
432 | template<typename _IteratorL, typename _IteratorR> |
433 | constexpr bool |
434 | operator==(const reverse_iterator<_IteratorL>& __x, |
435 | const reverse_iterator<_IteratorR>& __y) |
436 | requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; } |
437 | { return __x.base() == __y.base(); } |
438 | |
439 | template<typename _IteratorL, typename _IteratorR> |
440 | constexpr bool |
441 | operator!=(const reverse_iterator<_IteratorL>& __x, |
442 | const reverse_iterator<_IteratorR>& __y) |
443 | requires requires { { __x.base() != __y.base() } -> convertible_to<bool>; } |
444 | { return __x.base() != __y.base(); } |
445 | |
446 | template<typename _IteratorL, typename _IteratorR> |
447 | constexpr bool |
448 | operator<(const reverse_iterator<_IteratorL>& __x, |
449 | const reverse_iterator<_IteratorR>& __y) |
450 | requires requires { { __x.base() > __y.base() } -> convertible_to<bool>; } |
451 | { return __x.base() > __y.base(); } |
452 | |
453 | template<typename _IteratorL, typename _IteratorR> |
454 | constexpr bool |
455 | operator>(const reverse_iterator<_IteratorL>& __x, |
456 | const reverse_iterator<_IteratorR>& __y) |
457 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
458 | { return __x.base() < __y.base(); } |
459 | |
460 | template<typename _IteratorL, typename _IteratorR> |
461 | constexpr bool |
462 | operator<=(const reverse_iterator<_IteratorL>& __x, |
463 | const reverse_iterator<_IteratorR>& __y) |
464 | requires requires { { __x.base() >= __y.base() } -> convertible_to<bool>; } |
465 | { return __x.base() >= __y.base(); } |
466 | |
467 | template<typename _IteratorL, typename _IteratorR> |
468 | constexpr bool |
469 | operator>=(const reverse_iterator<_IteratorL>& __x, |
470 | const reverse_iterator<_IteratorR>& __y) |
471 | requires requires { { __x.base() <= __y.base() } -> convertible_to<bool>; } |
472 | { return __x.base() <= __y.base(); } |
473 | |
474 | template<typename _IteratorL, |
475 | three_way_comparable_with<_IteratorL> _IteratorR> |
476 | constexpr compare_three_way_result_t<_IteratorL, _IteratorR> |
477 | operator<=>(const reverse_iterator<_IteratorL>& __x, |
478 | const reverse_iterator<_IteratorR>& __y) |
479 | { return __y.base() <=> __x.base(); } |
480 | #endif // C++20 |
481 | //@} |
482 | |
483 | #if __cplusplus201703L < 201103L |
484 | template<typename _Iterator> |
485 | inline typename reverse_iterator<_Iterator>::difference_type |
486 | operator-(const reverse_iterator<_Iterator>& __x, |
487 | const reverse_iterator<_Iterator>& __y) |
488 | { return __y.base() - __x.base(); } |
489 | |
490 | template<typename _IteratorL, typename _IteratorR> |
491 | inline typename reverse_iterator<_IteratorL>::difference_type |
492 | operator-(const reverse_iterator<_IteratorL>& __x, |
493 | const reverse_iterator<_IteratorR>& __y) |
494 | { return __y.base() - __x.base(); } |
495 | #else |
496 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
497 | // DR 685. reverse_iterator/move_iterator difference has invalid signatures |
498 | template<typename _IteratorL, typename _IteratorR> |
499 | inline _GLIBCXX17_CONSTEXPRconstexpr auto |
500 | operator-(const reverse_iterator<_IteratorL>& __x, |
501 | const reverse_iterator<_IteratorR>& __y) |
502 | -> decltype(__y.base() - __x.base()) |
503 | { return __y.base() - __x.base(); } |
504 | #endif |
505 | |
506 | template<typename _Iterator> |
507 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
508 | operator+(typename reverse_iterator<_Iterator>::difference_type __n, |
509 | const reverse_iterator<_Iterator>& __x) |
510 | { return reverse_iterator<_Iterator>(__x.base() - __n); } |
511 | |
512 | #if __cplusplus201703L >= 201103L |
513 | // Same as C++14 make_reverse_iterator but used in C++11 mode too. |
514 | template<typename _Iterator> |
515 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
516 | __make_reverse_iterator(_Iterator __i) |
517 | { return reverse_iterator<_Iterator>(__i); } |
518 | |
519 | # if __cplusplus201703L >= 201402L |
520 | # define __cpp_lib_make_reverse_iterator201402 201402 |
521 | |
522 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
523 | // DR 2285. make_reverse_iterator |
524 | /// Generator function for reverse_iterator. |
525 | template<typename _Iterator> |
526 | inline _GLIBCXX17_CONSTEXPRconstexpr reverse_iterator<_Iterator> |
527 | make_reverse_iterator(_Iterator __i) |
528 | { return reverse_iterator<_Iterator>(__i); } |
529 | |
530 | # if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
531 | template<typename _Iterator1, typename _Iterator2> |
532 | requires (!sized_sentinel_for<_Iterator1, _Iterator2>) |
533 | inline constexpr bool |
534 | disable_sized_sentinel_for<reverse_iterator<_Iterator1>, |
535 | reverse_iterator<_Iterator2>> = true; |
536 | # endif // C++20 |
537 | # endif // C++14 |
538 | |
539 | template<typename _Iterator> |
540 | _GLIBCXX20_CONSTEXPR |
541 | auto |
542 | __niter_base(reverse_iterator<_Iterator> __it) |
543 | -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) |
544 | { return __make_reverse_iterator(__niter_base(__it.base())); } |
545 | |
546 | template<typename _Iterator> |
547 | struct __is_move_iterator<reverse_iterator<_Iterator> > |
548 | : __is_move_iterator<_Iterator> |
549 | { }; |
550 | |
551 | template<typename _Iterator> |
552 | _GLIBCXX20_CONSTEXPR |
553 | auto |
554 | __miter_base(reverse_iterator<_Iterator> __it) |
555 | -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) |
556 | { return __make_reverse_iterator(__miter_base(__it.base())); } |
557 | #endif // C++11 |
558 | |
559 | // 24.4.2.2.1 back_insert_iterator |
560 | /** |
561 | * @brief Turns assignment into insertion. |
562 | * |
563 | * These are output iterators, constructed from a container-of-T. |
564 | * Assigning a T to the iterator appends it to the container using |
565 | * push_back. |
566 | * |
567 | * Tip: Using the back_inserter function to create these iterators can |
568 | * save typing. |
569 | */ |
570 | template<typename _Container> |
571 | class back_insert_iterator |
572 | : public iterator<output_iterator_tag, void, void, void, void> |
573 | { |
574 | protected: |
575 | _Container* container; |
576 | |
577 | public: |
578 | /// A nested typedef for the type of whatever container you used. |
579 | typedef _Container container_type; |
580 | #if __cplusplus201703L > 201703L |
581 | using difference_type = ptrdiff_t; |
582 | |
583 | constexpr back_insert_iterator() noexcept : container(nullptr) { } |
584 | #endif |
585 | |
586 | /// The only way to create this %iterator is with a container. |
587 | explicit _GLIBCXX20_CONSTEXPR |
588 | back_insert_iterator(_Container& __x) |
589 | : container(std::__addressof(__x)) { } |
590 | |
591 | /** |
592 | * @param __value An instance of whatever type |
593 | * container_type::const_reference is; presumably a |
594 | * reference-to-const T for container<T>. |
595 | * @return This %iterator, for chained operations. |
596 | * |
597 | * This kind of %iterator doesn't really have a @a position in the |
598 | * container (you can think of the position as being permanently at |
599 | * the end, if you like). Assigning a value to the %iterator will |
600 | * always append the value to the end of the container. |
601 | */ |
602 | #if __cplusplus201703L < 201103L |
603 | back_insert_iterator& |
604 | operator=(typename _Container::const_reference __value) |
605 | { |
606 | container->push_back(__value); |
607 | return *this; |
608 | } |
609 | #else |
610 | _GLIBCXX20_CONSTEXPR |
611 | back_insert_iterator& |
612 | operator=(const typename _Container::value_type& __value) |
613 | { |
614 | container->push_back(__value); |
615 | return *this; |
616 | } |
617 | |
618 | _GLIBCXX20_CONSTEXPR |
619 | back_insert_iterator& |
620 | operator=(typename _Container::value_type&& __value) |
621 | { |
622 | container->push_back(std::move(__value)); |
623 | return *this; |
624 | } |
625 | #endif |
626 | |
627 | /// Simply returns *this. |
628 | _GLIBCXX20_CONSTEXPR |
629 | back_insert_iterator& |
630 | operator*() |
631 | { return *this; } |
632 | |
633 | /// Simply returns *this. (This %iterator does not @a move.) |
634 | _GLIBCXX20_CONSTEXPR |
635 | back_insert_iterator& |
636 | operator++() |
637 | { return *this; } |
638 | |
639 | /// Simply returns *this. (This %iterator does not @a move.) |
640 | _GLIBCXX20_CONSTEXPR |
641 | back_insert_iterator |
642 | operator++(int) |
643 | { return *this; } |
644 | }; |
645 | |
646 | /** |
647 | * @param __x A container of arbitrary type. |
648 | * @return An instance of back_insert_iterator working on @p __x. |
649 | * |
650 | * This wrapper function helps in creating back_insert_iterator instances. |
651 | * Typing the name of the %iterator requires knowing the precise full |
652 | * type of the container, which can be tedious and impedes generic |
653 | * programming. Using this function lets you take advantage of automatic |
654 | * template parameter deduction, making the compiler match the correct |
655 | * types for you. |
656 | */ |
657 | template<typename _Container> |
658 | _GLIBCXX20_CONSTEXPR |
659 | inline back_insert_iterator<_Container> |
660 | back_inserter(_Container& __x) |
661 | { return back_insert_iterator<_Container>(__x); } |
662 | |
663 | /** |
664 | * @brief Turns assignment into insertion. |
665 | * |
666 | * These are output iterators, constructed from a container-of-T. |
667 | * Assigning a T to the iterator prepends it to the container using |
668 | * push_front. |
669 | * |
670 | * Tip: Using the front_inserter function to create these iterators can |
671 | * save typing. |
672 | */ |
673 | template<typename _Container> |
674 | class front_insert_iterator |
675 | : public iterator<output_iterator_tag, void, void, void, void> |
676 | { |
677 | protected: |
678 | _Container* container; |
679 | |
680 | public: |
681 | /// A nested typedef for the type of whatever container you used. |
682 | typedef _Container container_type; |
683 | #if __cplusplus201703L > 201703L |
684 | using difference_type = ptrdiff_t; |
685 | |
686 | constexpr front_insert_iterator() noexcept : container(nullptr) { } |
687 | #endif |
688 | |
689 | /// The only way to create this %iterator is with a container. |
690 | explicit _GLIBCXX20_CONSTEXPR |
691 | front_insert_iterator(_Container& __x) |
692 | : container(std::__addressof(__x)) { } |
693 | |
694 | /** |
695 | * @param __value An instance of whatever type |
696 | * container_type::const_reference is; presumably a |
697 | * reference-to-const T for container<T>. |
698 | * @return This %iterator, for chained operations. |
699 | * |
700 | * This kind of %iterator doesn't really have a @a position in the |
701 | * container (you can think of the position as being permanently at |
702 | * the front, if you like). Assigning a value to the %iterator will |
703 | * always prepend the value to the front of the container. |
704 | */ |
705 | #if __cplusplus201703L < 201103L |
706 | front_insert_iterator& |
707 | operator=(typename _Container::const_reference __value) |
708 | { |
709 | container->push_front(__value); |
710 | return *this; |
711 | } |
712 | #else |
713 | _GLIBCXX20_CONSTEXPR |
714 | front_insert_iterator& |
715 | operator=(const typename _Container::value_type& __value) |
716 | { |
717 | container->push_front(__value); |
718 | return *this; |
719 | } |
720 | |
721 | _GLIBCXX20_CONSTEXPR |
722 | front_insert_iterator& |
723 | operator=(typename _Container::value_type&& __value) |
724 | { |
725 | container->push_front(std::move(__value)); |
726 | return *this; |
727 | } |
728 | #endif |
729 | |
730 | /// Simply returns *this. |
731 | _GLIBCXX20_CONSTEXPR |
732 | front_insert_iterator& |
733 | operator*() |
734 | { return *this; } |
735 | |
736 | /// Simply returns *this. (This %iterator does not @a move.) |
737 | _GLIBCXX20_CONSTEXPR |
738 | front_insert_iterator& |
739 | operator++() |
740 | { return *this; } |
741 | |
742 | /// Simply returns *this. (This %iterator does not @a move.) |
743 | _GLIBCXX20_CONSTEXPR |
744 | front_insert_iterator |
745 | operator++(int) |
746 | { return *this; } |
747 | }; |
748 | |
749 | /** |
750 | * @param __x A container of arbitrary type. |
751 | * @return An instance of front_insert_iterator working on @p x. |
752 | * |
753 | * This wrapper function helps in creating front_insert_iterator instances. |
754 | * Typing the name of the %iterator requires knowing the precise full |
755 | * type of the container, which can be tedious and impedes generic |
756 | * programming. Using this function lets you take advantage of automatic |
757 | * template parameter deduction, making the compiler match the correct |
758 | * types for you. |
759 | */ |
760 | template<typename _Container> |
761 | _GLIBCXX20_CONSTEXPR |
762 | inline front_insert_iterator<_Container> |
763 | front_inserter(_Container& __x) |
764 | { return front_insert_iterator<_Container>(__x); } |
765 | |
766 | /** |
767 | * @brief Turns assignment into insertion. |
768 | * |
769 | * These are output iterators, constructed from a container-of-T. |
770 | * Assigning a T to the iterator inserts it in the container at the |
771 | * %iterator's position, rather than overwriting the value at that |
772 | * position. |
773 | * |
774 | * (Sequences will actually insert a @e copy of the value before the |
775 | * %iterator's position.) |
776 | * |
777 | * Tip: Using the inserter function to create these iterators can |
778 | * save typing. |
779 | */ |
780 | template<typename _Container> |
781 | class insert_iterator |
782 | : public iterator<output_iterator_tag, void, void, void, void> |
783 | { |
784 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
785 | using _Iter = std::__detail::__range_iter_t<_Container>; |
786 | |
787 | protected: |
788 | _Container* container = nullptr; |
789 | _Iter iter = _Iter(); |
790 | #else |
791 | typedef typename _Container::iterator _Iter; |
792 | |
793 | protected: |
794 | _Container* container; |
795 | _Iter iter; |
796 | #endif |
797 | |
798 | public: |
799 | /// A nested typedef for the type of whatever container you used. |
800 | typedef _Container container_type; |
801 | |
802 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
803 | using difference_type = ptrdiff_t; |
804 | |
805 | insert_iterator() = default; |
806 | #endif |
807 | |
808 | /** |
809 | * The only way to create this %iterator is with a container and an |
810 | * initial position (a normal %iterator into the container). |
811 | */ |
812 | _GLIBCXX20_CONSTEXPR |
813 | insert_iterator(_Container& __x, _Iter __i) |
814 | : container(std::__addressof(__x)), iter(__i) {} |
815 | |
816 | /** |
817 | * @param __value An instance of whatever type |
818 | * container_type::const_reference is; presumably a |
819 | * reference-to-const T for container<T>. |
820 | * @return This %iterator, for chained operations. |
821 | * |
822 | * This kind of %iterator maintains its own position in the |
823 | * container. Assigning a value to the %iterator will insert the |
824 | * value into the container at the place before the %iterator. |
825 | * |
826 | * The position is maintained such that subsequent assignments will |
827 | * insert values immediately after one another. For example, |
828 | * @code |
829 | * // vector v contains A and Z |
830 | * |
831 | * insert_iterator i (v, ++v.begin()); |
832 | * i = 1; |
833 | * i = 2; |
834 | * i = 3; |
835 | * |
836 | * // vector v contains A, 1, 2, 3, and Z |
837 | * @endcode |
838 | */ |
839 | #if __cplusplus201703L < 201103L |
840 | insert_iterator& |
841 | operator=(typename _Container::const_reference __value) |
842 | { |
843 | iter = container->insert(iter, __value); |
844 | ++iter; |
845 | return *this; |
846 | } |
847 | #else |
848 | _GLIBCXX20_CONSTEXPR |
849 | insert_iterator& |
850 | operator=(const typename _Container::value_type& __value) |
851 | { |
852 | iter = container->insert(iter, __value); |
853 | ++iter; |
854 | return *this; |
855 | } |
856 | |
857 | _GLIBCXX20_CONSTEXPR |
858 | insert_iterator& |
859 | operator=(typename _Container::value_type&& __value) |
860 | { |
861 | iter = container->insert(iter, std::move(__value)); |
862 | ++iter; |
863 | return *this; |
864 | } |
865 | #endif |
866 | |
867 | /// Simply returns *this. |
868 | _GLIBCXX20_CONSTEXPR |
869 | insert_iterator& |
870 | operator*() |
871 | { return *this; } |
872 | |
873 | /// Simply returns *this. (This %iterator does not @a move.) |
874 | _GLIBCXX20_CONSTEXPR |
875 | insert_iterator& |
876 | operator++() |
877 | { return *this; } |
878 | |
879 | /// Simply returns *this. (This %iterator does not @a move.) |
880 | _GLIBCXX20_CONSTEXPR |
881 | insert_iterator& |
882 | operator++(int) |
883 | { return *this; } |
884 | }; |
885 | |
886 | /** |
887 | * @param __x A container of arbitrary type. |
888 | * @param __i An iterator into the container. |
889 | * @return An instance of insert_iterator working on @p __x. |
890 | * |
891 | * This wrapper function helps in creating insert_iterator instances. |
892 | * Typing the name of the %iterator requires knowing the precise full |
893 | * type of the container, which can be tedious and impedes generic |
894 | * programming. Using this function lets you take advantage of automatic |
895 | * template parameter deduction, making the compiler match the correct |
896 | * types for you. |
897 | */ |
898 | #if __cplusplus201703L > 201703L && defined __cpp_lib_concepts |
899 | template<typename _Container> |
900 | constexpr insert_iterator<_Container> |
901 | inserter(_Container& __x, std::__detail::__range_iter_t<_Container> __i) |
902 | { return insert_iterator<_Container>(__x, __i); } |
903 | #else |
904 | template<typename _Container, typename _Iterator> |
905 | inline insert_iterator<_Container> |
906 | inserter(_Container& __x, _Iterator __i) |
907 | { |
908 | return insert_iterator<_Container>(__x, |
909 | typename _Container::iterator(__i)); |
910 | } |
911 | #endif |
912 | |
913 | // @} group iterators |
914 | |
915 | _GLIBCXX_END_NAMESPACE_VERSION |
916 | } // namespace |
917 | |
918 | namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
919 | { |
920 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
921 | |
922 | // This iterator adapter is @a normal in the sense that it does not |
923 | // change the semantics of any of the operators of its iterator |
924 | // parameter. Its primary purpose is to convert an iterator that is |
925 | // not a class, e.g. a pointer, into an iterator that is a class. |
926 | // The _Container parameter exists solely so that different containers |
927 | // using this template can instantiate different types, even if the |
928 | // _Iterator parameter is the same. |
929 | template<typename _Iterator, typename _Container> |
930 | class __normal_iterator |
931 | { |
932 | protected: |
933 | _Iterator _M_current; |
934 | |
935 | typedef std::iterator_traits<_Iterator> __traits_type; |
936 | |
937 | public: |
938 | typedef _Iterator iterator_type; |
939 | typedef typename __traits_type::iterator_category iterator_category; |
940 | typedef typename __traits_type::value_type value_type; |
941 | typedef typename __traits_type::difference_type difference_type; |
942 | typedef typename __traits_type::reference reference; |
943 | typedef typename __traits_type::pointer pointer; |
944 | |
945 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
946 | using iterator_concept = std::__detail::__iter_concept<_Iterator>; |
947 | #endif |
948 | |
949 | _GLIBCXX_CONSTEXPRconstexpr __normal_iterator() _GLIBCXX_NOEXCEPTnoexcept |
950 | : _M_current(_Iterator()) { } |
951 | |
952 | explicit _GLIBCXX20_CONSTEXPR |
953 | __normal_iterator(const _Iterator& __i) _GLIBCXX_NOEXCEPTnoexcept |
954 | : _M_current(__i) { } |
955 | |
956 | // Allow iterator to const_iterator conversion |
957 | template<typename _Iter> |
958 | _GLIBCXX20_CONSTEXPR |
959 | __normal_iterator(const __normal_iterator<_Iter, |
960 | typename __enable_if< |
961 | (std::__are_same<_Iter, typename _Container::pointer>::__value), |
962 | _Container>::__type>& __i) _GLIBCXX_NOEXCEPTnoexcept |
963 | : _M_current(__i.base()) { } |
964 | |
965 | // Forward iterator requirements |
966 | _GLIBCXX20_CONSTEXPR |
967 | reference |
968 | operator*() const _GLIBCXX_NOEXCEPTnoexcept |
969 | { return *_M_current; } |
970 | |
971 | _GLIBCXX20_CONSTEXPR |
972 | pointer |
973 | operator->() const _GLIBCXX_NOEXCEPTnoexcept |
974 | { return _M_current; } |
975 | |
976 | _GLIBCXX20_CONSTEXPR |
977 | __normal_iterator& |
978 | operator++() _GLIBCXX_NOEXCEPTnoexcept |
979 | { |
980 | ++_M_current; |
981 | return *this; |
982 | } |
983 | |
984 | _GLIBCXX20_CONSTEXPR |
985 | __normal_iterator |
986 | operator++(int) _GLIBCXX_NOEXCEPTnoexcept |
987 | { return __normal_iterator(_M_current++); } |
988 | |
989 | // Bidirectional iterator requirements |
990 | _GLIBCXX20_CONSTEXPR |
991 | __normal_iterator& |
992 | operator--() _GLIBCXX_NOEXCEPTnoexcept |
993 | { |
994 | --_M_current; |
995 | return *this; |
996 | } |
997 | |
998 | _GLIBCXX20_CONSTEXPR |
999 | __normal_iterator |
1000 | operator--(int) _GLIBCXX_NOEXCEPTnoexcept |
1001 | { return __normal_iterator(_M_current--); } |
1002 | |
1003 | // Random access iterator requirements |
1004 | _GLIBCXX20_CONSTEXPR |
1005 | reference |
1006 | operator[](difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1007 | { return _M_current[__n]; } |
1008 | |
1009 | _GLIBCXX20_CONSTEXPR |
1010 | __normal_iterator& |
1011 | operator+=(difference_type __n) _GLIBCXX_NOEXCEPTnoexcept |
1012 | { _M_current += __n; return *this; } |
1013 | |
1014 | _GLIBCXX20_CONSTEXPR |
1015 | __normal_iterator |
1016 | operator+(difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1017 | { return __normal_iterator(_M_current + __n); } |
1018 | |
1019 | _GLIBCXX20_CONSTEXPR |
1020 | __normal_iterator& |
1021 | operator-=(difference_type __n) _GLIBCXX_NOEXCEPTnoexcept |
1022 | { _M_current -= __n; return *this; } |
1023 | |
1024 | _GLIBCXX20_CONSTEXPR |
1025 | __normal_iterator |
1026 | operator-(difference_type __n) const _GLIBCXX_NOEXCEPTnoexcept |
1027 | { return __normal_iterator(_M_current - __n); } |
1028 | |
1029 | _GLIBCXX20_CONSTEXPR |
1030 | const _Iterator& |
1031 | base() const _GLIBCXX_NOEXCEPTnoexcept |
1032 | { return _M_current; } |
1033 | }; |
1034 | |
1035 | // Note: In what follows, the left- and right-hand-side iterators are |
1036 | // allowed to vary in types (conceptually in cv-qualification) so that |
1037 | // comparison between cv-qualified and non-cv-qualified iterators be |
1038 | // valid. However, the greedy and unfriendly operators in std::rel_ops |
1039 | // will make overload resolution ambiguous (when in scope) if we don't |
1040 | // provide overloads whose operands are of the same type. Can someone |
1041 | // remind me what generic programming is about? -- Gaby |
1042 | |
1043 | #if __cpp_lib_three_way_comparison |
1044 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1045 | requires requires (_IteratorL __lhs, _IteratorR __rhs) |
1046 | { { __lhs == __rhs } -> std::convertible_to<bool>; } |
1047 | constexpr bool |
1048 | operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1049 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1050 | noexcept(noexcept(__lhs.base() == __rhs.base())) |
1051 | { return __lhs.base() == __rhs.base(); } |
1052 | |
1053 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1054 | constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL> |
1055 | operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1056 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1057 | noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) |
1058 | { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } |
1059 | #else |
1060 | // Forward iterator requirements |
1061 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1062 | _GLIBCXX20_CONSTEXPR |
1063 | inline bool |
1064 | operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1065 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1066 | _GLIBCXX_NOEXCEPTnoexcept |
1067 | { return __lhs.base() == __rhs.base(); } |
1068 | |
1069 | template<typename _Iterator, typename _Container> |
1070 | _GLIBCXX20_CONSTEXPR |
1071 | inline bool |
1072 | operator==(const __normal_iterator<_Iterator, _Container>& __lhs, |
1073 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1074 | _GLIBCXX_NOEXCEPTnoexcept |
1075 | { return __lhs.base() == __rhs.base(); } |
1076 | |
1077 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1078 | _GLIBCXX20_CONSTEXPR |
1079 | inline bool |
1080 | operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1081 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1082 | _GLIBCXX_NOEXCEPTnoexcept |
1083 | { return __lhs.base() != __rhs.base(); } |
1084 | |
1085 | template<typename _Iterator, typename _Container> |
1086 | _GLIBCXX20_CONSTEXPR |
1087 | inline bool |
1088 | operator!=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1089 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1090 | _GLIBCXX_NOEXCEPTnoexcept |
1091 | { return __lhs.base() != __rhs.base(); } |
1092 | |
1093 | // Random access iterator requirements |
1094 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1095 | inline bool |
1096 | operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1097 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1098 | _GLIBCXX_NOEXCEPTnoexcept |
1099 | { return __lhs.base() < __rhs.base(); } |
1100 | |
1101 | template<typename _Iterator, typename _Container> |
1102 | _GLIBCXX20_CONSTEXPR |
1103 | inline bool |
1104 | operator<(const __normal_iterator<_Iterator, _Container>& __lhs, |
1105 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1106 | _GLIBCXX_NOEXCEPTnoexcept |
1107 | { return __lhs.base() < __rhs.base(); } |
1108 | |
1109 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1110 | inline bool |
1111 | operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1112 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1113 | _GLIBCXX_NOEXCEPTnoexcept |
1114 | { return __lhs.base() > __rhs.base(); } |
1115 | |
1116 | template<typename _Iterator, typename _Container> |
1117 | _GLIBCXX20_CONSTEXPR |
1118 | inline bool |
1119 | operator>(const __normal_iterator<_Iterator, _Container>& __lhs, |
1120 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1121 | _GLIBCXX_NOEXCEPTnoexcept |
1122 | { return __lhs.base() > __rhs.base(); } |
1123 | |
1124 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1125 | inline bool |
1126 | operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1127 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1128 | _GLIBCXX_NOEXCEPTnoexcept |
1129 | { return __lhs.base() <= __rhs.base(); } |
1130 | |
1131 | template<typename _Iterator, typename _Container> |
1132 | _GLIBCXX20_CONSTEXPR |
1133 | inline bool |
1134 | operator<=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1135 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1136 | _GLIBCXX_NOEXCEPTnoexcept |
1137 | { return __lhs.base() <= __rhs.base(); } |
1138 | |
1139 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1140 | inline bool |
1141 | operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1142 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1143 | _GLIBCXX_NOEXCEPTnoexcept |
1144 | { return __lhs.base() >= __rhs.base(); } |
1145 | |
1146 | template<typename _Iterator, typename _Container> |
1147 | _GLIBCXX20_CONSTEXPR |
1148 | inline bool |
1149 | operator>=(const __normal_iterator<_Iterator, _Container>& __lhs, |
1150 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1151 | _GLIBCXX_NOEXCEPTnoexcept |
1152 | { return __lhs.base() >= __rhs.base(); } |
1153 | #endif // three-way comparison |
1154 | |
1155 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1156 | // According to the resolution of DR179 not only the various comparison |
1157 | // operators but also operator- must accept mixed iterator/const_iterator |
1158 | // parameters. |
1159 | template<typename _IteratorL, typename _IteratorR, typename _Container> |
1160 | #if __cplusplus201703L >= 201103L |
1161 | // DR 685. |
1162 | _GLIBCXX20_CONSTEXPR |
1163 | inline auto |
1164 | operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1165 | const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept |
1166 | -> decltype(__lhs.base() - __rhs.base()) |
1167 | #else |
1168 | inline typename __normal_iterator<_IteratorL, _Container>::difference_type |
1169 | operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, |
1170 | const __normal_iterator<_IteratorR, _Container>& __rhs) |
1171 | #endif |
1172 | { return __lhs.base() - __rhs.base(); } |
1173 | |
1174 | template<typename _Iterator, typename _Container> |
1175 | _GLIBCXX20_CONSTEXPR |
1176 | inline typename __normal_iterator<_Iterator, _Container>::difference_type |
1177 | operator-(const __normal_iterator<_Iterator, _Container>& __lhs, |
1178 | const __normal_iterator<_Iterator, _Container>& __rhs) |
1179 | _GLIBCXX_NOEXCEPTnoexcept |
1180 | { return __lhs.base() - __rhs.base(); } |
1181 | |
1182 | template<typename _Iterator, typename _Container> |
1183 | _GLIBCXX20_CONSTEXPR |
1184 | inline __normal_iterator<_Iterator, _Container> |
1185 | operator+(typename __normal_iterator<_Iterator, _Container>::difference_type |
1186 | __n, const __normal_iterator<_Iterator, _Container>& __i) |
1187 | _GLIBCXX_NOEXCEPTnoexcept |
1188 | { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); } |
1189 | |
1190 | _GLIBCXX_END_NAMESPACE_VERSION |
1191 | } // namespace |
1192 | |
1193 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
1194 | { |
1195 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
1196 | |
1197 | template<typename _Iterator, typename _Container> |
1198 | _GLIBCXX20_CONSTEXPR |
1199 | _Iterator |
1200 | __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) |
1201 | _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)noexcept(std::is_nothrow_copy_constructible<_Iterator>:: value) |
1202 | { return __it.base(); } |
1203 | |
1204 | #if __cplusplus201703L >= 201103L |
1205 | /** |
1206 | * @addtogroup iterators |
1207 | * @{ |
1208 | */ |
1209 | |
1210 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1211 | template<semiregular _Sent> |
1212 | class move_sentinel |
1213 | { |
1214 | public: |
1215 | constexpr |
1216 | move_sentinel() |
1217 | noexcept(is_nothrow_default_constructible_v<_Sent>) |
1218 | : _M_last() { } |
1219 | |
1220 | constexpr explicit |
1221 | move_sentinel(_Sent __s) |
1222 | noexcept(is_nothrow_move_constructible_v<_Sent>) |
1223 | : _M_last(std::move(__s)) { } |
1224 | |
1225 | template<typename _S2> requires convertible_to<const _S2&, _Sent> |
1226 | constexpr |
1227 | move_sentinel(const move_sentinel<_S2>& __s) |
1228 | noexcept(is_nothrow_constructible_v<_Sent, const _S2&>) |
1229 | : _M_last(__s.base()) |
1230 | { } |
1231 | |
1232 | template<typename _S2> requires assignable_from<_Sent&, const _S2&> |
1233 | constexpr move_sentinel& |
1234 | operator=(const move_sentinel<_S2>& __s) |
1235 | noexcept(is_nothrow_assignable_v<_Sent, const _S2&>) |
1236 | { |
1237 | _M_last = __s.base(); |
1238 | return *this; |
1239 | } |
1240 | |
1241 | constexpr _Sent |
1242 | base() const |
1243 | noexcept(is_nothrow_copy_constructible_v<_Sent>) |
1244 | { return _M_last; } |
1245 | |
1246 | private: |
1247 | _Sent _M_last; |
1248 | }; |
1249 | #endif // C++20 |
1250 | |
1251 | // 24.4.3 Move iterators |
1252 | /** |
1253 | * Class template move_iterator is an iterator adapter with the same |
1254 | * behavior as the underlying iterator except that its dereference |
1255 | * operator implicitly converts the value returned by the underlying |
1256 | * iterator's dereference operator to an rvalue reference. Some |
1257 | * generic algorithms can be called with move iterators to replace |
1258 | * copying with moving. |
1259 | */ |
1260 | template<typename _Iterator> |
1261 | class move_iterator |
1262 | { |
1263 | _Iterator _M_current; |
1264 | |
1265 | using __traits_type = iterator_traits<_Iterator>; |
1266 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1267 | using __base_cat = typename __traits_type::iterator_category; |
1268 | #else |
1269 | using __base_ref = typename __traits_type::reference; |
1270 | #endif |
1271 | |
1272 | public: |
1273 | using iterator_type = _Iterator; |
1274 | |
1275 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1276 | using iterator_concept = input_iterator_tag; |
1277 | using iterator_category |
1278 | = __detail::__clamp_iter_cat<__base_cat, random_access_iterator_tag>; |
1279 | using value_type = iter_value_t<_Iterator>; |
1280 | using difference_type = iter_difference_t<_Iterator>; |
1281 | using pointer = _Iterator; |
1282 | using reference = iter_rvalue_reference_t<_Iterator>; |
1283 | #else |
1284 | typedef typename __traits_type::iterator_category iterator_category; |
1285 | typedef typename __traits_type::value_type value_type; |
1286 | typedef typename __traits_type::difference_type difference_type; |
1287 | // NB: DR 680. |
1288 | typedef _Iterator pointer; |
1289 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1290 | // 2106. move_iterator wrapping iterators returning prvalues |
1291 | typedef typename conditional<is_reference<__base_ref>::value, |
1292 | typename remove_reference<__base_ref>::type&&, |
1293 | __base_ref>::type reference; |
1294 | #endif |
1295 | |
1296 | _GLIBCXX17_CONSTEXPRconstexpr |
1297 | move_iterator() |
1298 | : _M_current() { } |
1299 | |
1300 | explicit _GLIBCXX17_CONSTEXPRconstexpr |
1301 | move_iterator(iterator_type __i) |
1302 | : _M_current(std::move(__i)) { } |
1303 | |
1304 | template<typename _Iter> |
1305 | _GLIBCXX17_CONSTEXPRconstexpr |
1306 | move_iterator(const move_iterator<_Iter>& __i) |
1307 | : _M_current(__i.base()) { } |
1308 | |
1309 | #if __cplusplus201703L <= 201703L |
1310 | _GLIBCXX17_CONSTEXPRconstexpr iterator_type |
1311 | base() const |
1312 | { return _M_current; } |
1313 | #else |
1314 | constexpr iterator_type |
1315 | base() const & |
1316 | #if __cpp_lib_concepts |
1317 | requires copy_constructible<iterator_type> |
1318 | #endif |
1319 | { return _M_current; } |
1320 | |
1321 | constexpr iterator_type |
1322 | base() && |
1323 | { return std::move(_M_current); } |
1324 | #endif |
1325 | |
1326 | _GLIBCXX17_CONSTEXPRconstexpr reference |
1327 | operator*() const |
1328 | { return static_cast<reference>(*_M_current); } |
1329 | |
1330 | _GLIBCXX17_CONSTEXPRconstexpr pointer |
1331 | operator->() const |
1332 | { return _M_current; } |
1333 | |
1334 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1335 | operator++() |
1336 | { |
1337 | ++_M_current; |
1338 | return *this; |
1339 | } |
1340 | |
1341 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1342 | operator++(int) |
1343 | { |
1344 | move_iterator __tmp = *this; |
1345 | ++_M_current; |
1346 | return __tmp; |
1347 | } |
1348 | |
1349 | #if __cpp_lib_concepts |
1350 | constexpr void |
1351 | operator++(int) requires (!forward_iterator<_Iterator>) |
1352 | { ++_M_current; } |
1353 | #endif |
1354 | |
1355 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1356 | operator--() |
1357 | { |
1358 | --_M_current; |
1359 | return *this; |
1360 | } |
1361 | |
1362 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1363 | operator--(int) |
1364 | { |
1365 | move_iterator __tmp = *this; |
1366 | --_M_current; |
1367 | return __tmp; |
1368 | } |
1369 | |
1370 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1371 | operator+(difference_type __n) const |
1372 | { return move_iterator(_M_current + __n); } |
1373 | |
1374 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1375 | operator+=(difference_type __n) |
1376 | { |
1377 | _M_current += __n; |
1378 | return *this; |
1379 | } |
1380 | |
1381 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator |
1382 | operator-(difference_type __n) const |
1383 | { return move_iterator(_M_current - __n); } |
1384 | |
1385 | _GLIBCXX17_CONSTEXPRconstexpr move_iterator& |
1386 | operator-=(difference_type __n) |
1387 | { |
1388 | _M_current -= __n; |
1389 | return *this; |
1390 | } |
1391 | |
1392 | _GLIBCXX17_CONSTEXPRconstexpr reference |
1393 | operator[](difference_type __n) const |
1394 | { return std::move(_M_current[__n]); } |
1395 | |
1396 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1397 | template<sentinel_for<_Iterator> _Sent> |
1398 | friend constexpr bool |
1399 | operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) |
1400 | { return __x.base() == __y.base(); } |
1401 | |
1402 | template<sized_sentinel_for<_Iterator> _Sent> |
1403 | friend constexpr iter_difference_t<_Iterator> |
1404 | operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) |
1405 | { return __x.base() - __y.base(); } |
1406 | |
1407 | template<sized_sentinel_for<_Iterator> _Sent> |
1408 | friend constexpr iter_difference_t<_Iterator> |
1409 | operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) |
1410 | { return __x.base() - __y.base(); } |
1411 | |
1412 | friend constexpr iter_rvalue_reference_t<_Iterator> |
1413 | iter_move(const move_iterator& __i) |
1414 | noexcept(noexcept(ranges::iter_move(__i._M_current))) |
1415 | { return ranges::iter_move(__i._M_current); } |
1416 | |
1417 | template<indirectly_swappable<_Iterator> _Iter2> |
1418 | friend constexpr void |
1419 | iter_swap(const move_iterator& __x, const move_iterator<_Iter2>& __y) |
1420 | noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) |
1421 | { return ranges::iter_swap(__x._M_current, __y._M_current); } |
1422 | #endif // C++20 |
1423 | }; |
1424 | |
1425 | template<typename _IteratorL, typename _IteratorR> |
1426 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1427 | operator==(const move_iterator<_IteratorL>& __x, |
1428 | const move_iterator<_IteratorR>& __y) |
1429 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1430 | requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; } |
1431 | #endif |
1432 | { return __x.base() == __y.base(); } |
1433 | |
1434 | #if __cpp_lib_three_way_comparison |
1435 | template<typename _IteratorL, |
1436 | three_way_comparable_with<_IteratorL> _IteratorR> |
1437 | constexpr compare_three_way_result_t<_IteratorL, _IteratorR> |
1438 | operator<=>(const move_iterator<_IteratorL>& __x, |
1439 | const move_iterator<_IteratorR>& __y) |
1440 | { return __x.base() <=> __y.base(); } |
1441 | #else |
1442 | template<typename _IteratorL, typename _IteratorR> |
1443 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1444 | operator!=(const move_iterator<_IteratorL>& __x, |
1445 | const move_iterator<_IteratorR>& __y) |
1446 | { return !(__x == __y); } |
1447 | #endif |
1448 | |
1449 | template<typename _IteratorL, typename _IteratorR> |
1450 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1451 | operator<(const move_iterator<_IteratorL>& __x, |
1452 | const move_iterator<_IteratorR>& __y) |
1453 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1454 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
1455 | #endif |
1456 | { return __x.base() < __y.base(); } |
1457 | |
1458 | template<typename _IteratorL, typename _IteratorR> |
1459 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1460 | operator<=(const move_iterator<_IteratorL>& __x, |
1461 | const move_iterator<_IteratorR>& __y) |
1462 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1463 | requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; } |
1464 | #endif |
1465 | { return !(__y < __x); } |
1466 | |
1467 | template<typename _IteratorL, typename _IteratorR> |
1468 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1469 | operator>(const move_iterator<_IteratorL>& __x, |
1470 | const move_iterator<_IteratorR>& __y) |
1471 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1472 | requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; } |
1473 | #endif |
1474 | { return __y < __x; } |
1475 | |
1476 | template<typename _IteratorL, typename _IteratorR> |
1477 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1478 | operator>=(const move_iterator<_IteratorL>& __x, |
1479 | const move_iterator<_IteratorR>& __y) |
1480 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1481 | requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; } |
1482 | #endif |
1483 | { return !(__x < __y); } |
1484 | |
1485 | #if ! (__cplusplus201703L > 201703L && __cpp_lib_concepts) |
1486 | // Note: See __normal_iterator operators note from Gaby to understand |
1487 | // why we have these extra overloads for some move_iterator operators. |
1488 | |
1489 | // These extra overloads are not needed in C++20, because the ones above |
1490 | // are constrained with a requires-clause and so overload resolution will |
1491 | // prefer them to greedy unconstrained function templates. |
1492 | |
1493 | template<typename _Iterator> |
1494 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1495 | operator==(const move_iterator<_Iterator>& __x, |
1496 | const move_iterator<_Iterator>& __y) |
1497 | { return __x.base() == __y.base(); } |
1498 | |
1499 | template<typename _Iterator> |
1500 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1501 | operator!=(const move_iterator<_Iterator>& __x, |
1502 | const move_iterator<_Iterator>& __y) |
1503 | { return !(__x == __y); } |
1504 | |
1505 | template<typename _Iterator> |
1506 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1507 | operator<(const move_iterator<_Iterator>& __x, |
1508 | const move_iterator<_Iterator>& __y) |
1509 | { return __x.base() < __y.base(); } |
1510 | |
1511 | template<typename _Iterator> |
1512 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1513 | operator<=(const move_iterator<_Iterator>& __x, |
1514 | const move_iterator<_Iterator>& __y) |
1515 | { return !(__y < __x); } |
1516 | |
1517 | template<typename _Iterator> |
1518 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1519 | operator>(const move_iterator<_Iterator>& __x, |
1520 | const move_iterator<_Iterator>& __y) |
1521 | { return __y < __x; } |
1522 | |
1523 | template<typename _Iterator> |
1524 | inline _GLIBCXX17_CONSTEXPRconstexpr bool |
1525 | operator>=(const move_iterator<_Iterator>& __x, |
1526 | const move_iterator<_Iterator>& __y) |
1527 | { return !(__x < __y); } |
1528 | #endif // ! C++20 |
1529 | |
1530 | // DR 685. |
1531 | template<typename _IteratorL, typename _IteratorR> |
1532 | inline _GLIBCXX17_CONSTEXPRconstexpr auto |
1533 | operator-(const move_iterator<_IteratorL>& __x, |
1534 | const move_iterator<_IteratorR>& __y) |
1535 | -> decltype(__x.base() - __y.base()) |
1536 | { return __x.base() - __y.base(); } |
1537 | |
1538 | template<typename _Iterator> |
1539 | inline _GLIBCXX17_CONSTEXPRconstexpr move_iterator<_Iterator> |
1540 | operator+(typename move_iterator<_Iterator>::difference_type __n, |
1541 | const move_iterator<_Iterator>& __x) |
1542 | { return __x + __n; } |
1543 | |
1544 | template<typename _Iterator> |
1545 | inline _GLIBCXX17_CONSTEXPRconstexpr move_iterator<_Iterator> |
1546 | make_move_iterator(_Iterator __i) |
1547 | { return move_iterator<_Iterator>(std::move(__i)); } |
1548 | |
1549 | template<typename _Iterator, typename _ReturnType |
1550 | = typename conditional<__move_if_noexcept_cond |
1551 | <typename iterator_traits<_Iterator>::value_type>::value, |
1552 | _Iterator, move_iterator<_Iterator>>::type> |
1553 | inline _GLIBCXX17_CONSTEXPRconstexpr _ReturnType |
1554 | __make_move_if_noexcept_iterator(_Iterator __i) |
1555 | { return _ReturnType(__i); } |
1556 | |
1557 | // Overload for pointers that matches std::move_if_noexcept more closely, |
1558 | // returning a constant iterator when we don't want to move. |
1559 | template<typename _Tp, typename _ReturnType |
1560 | = typename conditional<__move_if_noexcept_cond<_Tp>::value, |
1561 | const _Tp*, move_iterator<_Tp*>>::type> |
1562 | inline _GLIBCXX17_CONSTEXPRconstexpr _ReturnType |
1563 | __make_move_if_noexcept_iterator(_Tp* __i) |
1564 | { return _ReturnType(__i); } |
1565 | |
1566 | #if __cplusplus201703L > 201703L && __cpp_lib_concepts |
1567 | // [iterators.common] Common iterators |
1568 | |
1569 | namespace __detail |
1570 | { |
1571 | template<typename _It> |
1572 | concept __common_iter_has_arrow = indirectly_readable<const _It> |
1573 | && (requires(const _It& __it) { __it.operator->(); } |
1574 | || is_reference_v<iter_reference_t<_It>> |
1575 | || constructible_from<iter_value_t<_It>, iter_reference_t<_It>>); |
1576 | |
1577 | } // namespace __detail |
1578 | |
1579 | /// An iterator/sentinel adaptor for representing a non-common range. |
1580 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
1581 | requires (!same_as<_It, _Sent>) && copyable<_It> |
1582 | class common_iterator |
1583 | { |
1584 | template<typename _Tp, typename _Up> |
1585 | static constexpr bool |
1586 | _S_noexcept1() |
1587 | { |
1588 | if constexpr (is_trivially_default_constructible_v<_Tp>) |
1589 | return is_nothrow_assignable_v<_Tp, _Up>; |
1590 | else |
1591 | return is_nothrow_constructible_v<_Tp, _Up>; |
1592 | } |
1593 | |
1594 | template<typename _It2, typename _Sent2> |
1595 | static constexpr bool |
1596 | _S_noexcept() |
1597 | { return _S_noexcept1<_It, _It2>() && _S_noexcept1<_Sent, _Sent2>(); } |
1598 | |
1599 | class _Proxy |
1600 | { |
1601 | iter_value_t<_It> _M_keep; |
1602 | |
1603 | _Proxy(iter_reference_t<_It>&& __x) |
1604 | : _M_keep(std::move(__x)) { } |
1605 | |
1606 | friend class common_iterator; |
1607 | |
1608 | public: |
1609 | const iter_value_t<_It>* |
1610 | operator->() const |
1611 | { return std::__addressof(_M_keep); } |
1612 | }; |
1613 | |
1614 | public: |
1615 | constexpr |
1616 | common_iterator() |
1617 | noexcept(is_nothrow_default_constructible_v<_It>) |
1618 | : _M_it(), _M_index(0) |
1619 | { } |
1620 | |
1621 | constexpr |
1622 | common_iterator(_It __i) |
1623 | noexcept(is_nothrow_move_constructible_v<_It>) |
1624 | : _M_it(std::move(__i)), _M_index(0) |
1625 | { } |
1626 | |
1627 | constexpr |
1628 | common_iterator(_Sent __s) |
1629 | noexcept(is_nothrow_move_constructible_v<_Sent>) |
1630 | : _M_sent(std::move(__s)), _M_index(1) |
1631 | { } |
1632 | |
1633 | template<typename _It2, typename _Sent2> |
1634 | requires convertible_to<const _It2&, _It> |
1635 | && convertible_to<const _Sent2&, _Sent> |
1636 | constexpr |
1637 | common_iterator(const common_iterator<_It2, _Sent2>& __x) |
1638 | noexcept(_S_noexcept<const _It2&, const _Sent2&>()) |
1639 | : _M_valueless(), _M_index(__x._M_index) |
1640 | { |
1641 | if (_M_index == 0) |
1642 | { |
1643 | if constexpr (is_trivially_default_constructible_v<_It>) |
1644 | _M_it = std::move(__x._M_it); |
1645 | else |
1646 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1647 | } |
1648 | else if (_M_index == 1) |
1649 | { |
1650 | if constexpr (is_trivially_default_constructible_v<_Sent>) |
1651 | _M_sent = std::move(__x._M_sent); |
1652 | else |
1653 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1654 | } |
1655 | } |
1656 | |
1657 | constexpr |
1658 | common_iterator(const common_iterator& __x) |
1659 | noexcept(_S_noexcept<const _It&, const _Sent&>()) |
1660 | : _M_valueless(), _M_index(__x._M_index) |
1661 | { |
1662 | if (_M_index == 0) |
1663 | { |
1664 | if constexpr (is_trivially_default_constructible_v<_It>) |
1665 | _M_it = std::move(__x._M_it); |
1666 | else |
1667 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1668 | } |
1669 | else if (_M_index == 1) |
1670 | { |
1671 | if constexpr (is_trivially_default_constructible_v<_Sent>) |
1672 | _M_sent = std::move(__x._M_sent); |
1673 | else |
1674 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1675 | } |
1676 | } |
1677 | |
1678 | common_iterator& |
1679 | operator=(const common_iterator& __x) |
1680 | noexcept(is_nothrow_copy_assignable_v<_It> |
1681 | && is_nothrow_copy_assignable_v<_Sent> |
1682 | && is_nothrow_copy_constructible_v<_It> |
1683 | && is_nothrow_copy_constructible_v<_Sent>) |
1684 | { |
1685 | return this->operator=<_It, _Sent>(__x); |
1686 | } |
1687 | |
1688 | template<typename _It2, typename _Sent2> |
1689 | requires convertible_to<const _It2&, _It> |
1690 | && convertible_to<const _Sent2&, _Sent> |
1691 | && assignable_from<_It&, const _It2&> |
1692 | && assignable_from<_Sent&, const _Sent2&> |
1693 | common_iterator& |
1694 | operator=(const common_iterator<_It2, _Sent2>& __x) |
1695 | noexcept(is_nothrow_constructible_v<_It, const _It2&> |
1696 | && is_nothrow_constructible_v<_Sent, const _Sent2&> |
1697 | && is_nothrow_assignable_v<_It, const _It2&> |
1698 | && is_nothrow_assignable_v<_Sent, const _Sent2&>) |
1699 | { |
1700 | switch(_M_index << 2 | __x._M_index) |
1701 | { |
1702 | case 0b0000: |
1703 | _M_it = __x._M_it; |
1704 | break; |
1705 | case 0b0101: |
1706 | _M_sent = __x._M_sent; |
1707 | break; |
1708 | case 0b0001: |
1709 | _M_it.~_It(); |
1710 | _M_index = -1; |
1711 | [[fallthrough]]; |
1712 | case 0b1001: |
1713 | ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); |
1714 | _M_index = 1; |
1715 | break; |
1716 | case 0b0100: |
1717 | _M_sent.~_Sent(); |
1718 | _M_index = -1; |
1719 | [[fallthrough]]; |
1720 | case 0b1000: |
1721 | ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); |
1722 | _M_index = 0; |
1723 | break; |
1724 | default: |
1725 | __glibcxx_assert(__x._M_has_value()); |
1726 | __builtin_unreachable(); |
1727 | } |
1728 | return *this; |
1729 | } |
1730 | |
1731 | ~common_iterator() |
1732 | { |
1733 | switch (_M_index) |
1734 | { |
1735 | case 0: |
1736 | _M_it.~_It(); |
1737 | break; |
1738 | case 1: |
1739 | _M_sent.~_Sent(); |
1740 | break; |
1741 | } |
1742 | } |
1743 | |
1744 | decltype(auto) |
1745 | operator*() |
1746 | { |
1747 | __glibcxx_assert(_M_index == 0); |
1748 | return *_M_it; |
1749 | } |
1750 | |
1751 | decltype(auto) |
1752 | operator*() const requires __detail::__dereferenceable<const _It> |
1753 | { |
1754 | __glibcxx_assert(_M_index == 0); |
1755 | return *_M_it; |
1756 | } |
1757 | |
1758 | decltype(auto) |
1759 | operator->() const requires __detail::__common_iter_has_arrow<_It> |
1760 | { |
1761 | __glibcxx_assert(_M_index == 0); |
1762 | if constexpr (is_pointer_v<_It> || requires { _M_it.operator->(); }) |
1763 | return _M_it; |
1764 | else if constexpr (is_reference_v<iter_reference_t<_It>>) |
1765 | { |
1766 | auto&& __tmp = *_M_it; |
1767 | return std::__addressof(__tmp); |
1768 | } |
1769 | else |
1770 | return _Proxy{*_M_it}; |
1771 | } |
1772 | |
1773 | common_iterator& |
1774 | operator++() |
1775 | { |
1776 | __glibcxx_assert(_M_index == 0); |
1777 | ++_M_it; |
1778 | return *this; |
1779 | } |
1780 | |
1781 | decltype(auto) |
1782 | operator++(int) |
1783 | { |
1784 | __glibcxx_assert(_M_index == 0); |
1785 | if constexpr (forward_iterator<_It>) |
1786 | { |
1787 | common_iterator __tmp = *this; |
1788 | ++*this; |
1789 | return __tmp; |
1790 | } |
1791 | else |
1792 | return _M_it++; |
1793 | } |
1794 | |
1795 | template<typename _It2, sentinel_for<_It> _Sent2> |
1796 | requires sentinel_for<_Sent, _It2> |
1797 | friend bool |
1798 | operator==(const common_iterator& __x, |
1799 | const common_iterator<_It2, _Sent2>& __y) |
1800 | { |
1801 | switch(__x._M_index << 2 | __y._M_index) |
1802 | { |
1803 | case 0b0000: |
1804 | case 0b0101: |
1805 | return true; |
1806 | case 0b0001: |
1807 | return __x._M_it == __y._M_sent; |
1808 | case 0b0100: |
1809 | return __x._M_sent == __y._M_it; |
1810 | default: |
1811 | __glibcxx_assert(__x._M_has_value()); |
1812 | __glibcxx_assert(__y._M_has_value()); |
1813 | __builtin_unreachable(); |
1814 | } |
1815 | } |
1816 | |
1817 | template<typename _It2, sentinel_for<_It> _Sent2> |
1818 | requires sentinel_for<_Sent, _It2> && equality_comparable_with<_It, _It2> |
1819 | friend bool |
1820 | operator==(const common_iterator& __x, |
1821 | const common_iterator<_It2, _Sent2>& __y) |
1822 | { |
1823 | switch(__x._M_index << 2 | __y._M_index) |
1824 | { |
1825 | case 0b0101: |
1826 | return true; |
1827 | case 0b0000: |
1828 | return __x._M_it == __y._M_it; |
1829 | case 0b0001: |
1830 | return __x._M_it == __y._M_sent; |
1831 | case 0b0100: |
1832 | return __x._M_sent == __y._M_it; |
1833 | default: |
1834 | __glibcxx_assert(__x._M_has_value()); |
1835 | __glibcxx_assert(__y._M_has_value()); |
1836 | __builtin_unreachable(); |
1837 | } |
1838 | } |
1839 | |
1840 | template<sized_sentinel_for<_It> _It2, sized_sentinel_for<_It> _Sent2> |
1841 | requires sized_sentinel_for<_Sent, _It2> |
1842 | friend iter_difference_t<_It2> |
1843 | operator-(const common_iterator& __x, |
1844 | const common_iterator<_It2, _Sent2>& __y) |
1845 | { |
1846 | switch(__x._M_index << 2 | __y._M_index) |
1847 | { |
1848 | case 0b0101: |
1849 | return 0; |
1850 | case 0b0000: |
1851 | return __x._M_it - __y._M_it; |
1852 | case 0b0001: |
1853 | return __x._M_it - __y._M_sent; |
1854 | case 0b0100: |
1855 | return __x._M_sent - __y._M_it; |
1856 | default: |
1857 | __glibcxx_assert(__x._M_has_value()); |
1858 | __glibcxx_assert(__y._M_has_value()); |
1859 | __builtin_unreachable(); |
1860 | } |
1861 | } |
1862 | |
1863 | friend iter_rvalue_reference_t<_It> |
1864 | iter_move(const common_iterator& __i) |
1865 | noexcept(noexcept(ranges::iter_move(std::declval<const _It&>()))) |
1866 | requires input_iterator<_It> |
1867 | { |
1868 | __glibcxx_assert(__i._M_index == 0); |
1869 | return ranges::iter_move(__i._M_it); |
1870 | } |
1871 | |
1872 | template<indirectly_swappable<_It> _It2, typename _Sent2> |
1873 | friend void |
1874 | iter_swap(const common_iterator& __x, |
1875 | const common_iterator<_It2, _Sent2>& __y) |
1876 | noexcept(noexcept(ranges::iter_swap(std::declval<const _It&>(), |
1877 | std::declval<const _It2&>()))) |
1878 | { |
1879 | __glibcxx_assert(__x._M_index == 0); |
1880 | __glibcxx_assert(__y._M_index == 0); |
1881 | return ranges::iter_swap(__x._M_it, __y._M_it); |
1882 | } |
1883 | |
1884 | private: |
1885 | template<input_or_output_iterator _It2, sentinel_for<_It2> _Sent2> |
1886 | friend class common_iterator; |
1887 | |
1888 | bool _M_has_value() const noexcept { return _M_index < 2; } |
1889 | |
1890 | union |
1891 | { |
1892 | _It _M_it; |
1893 | _Sent _M_sent; |
1894 | unsigned char _M_valueless; |
1895 | }; |
1896 | unsigned char _M_index; // 0==_M_it, 1==_M_sent, 2==valueless |
1897 | }; |
1898 | |
1899 | template<typename _It, typename _Sent> |
1900 | struct incrementable_traits<common_iterator<_It, _Sent>> |
1901 | { |
1902 | using difference_type = iter_difference_t<_It>; |
1903 | }; |
1904 | |
1905 | namespace __detail |
1906 | { |
1907 | // FIXME: This has to be at namespace-scope because of PR 92103. |
1908 | template<typename _It, typename _Sent> |
1909 | struct __common_iter_ptr |
1910 | { |
1911 | using type = void; |
1912 | }; |
1913 | |
1914 | template<typename _It, typename _Sent> |
1915 | requires __detail::__common_iter_has_arrow<_It> |
1916 | struct __common_iter_ptr<_It, _Sent> |
1917 | { |
1918 | using common_iterator = std::common_iterator<_It, _Sent>; |
1919 | |
1920 | using type |
1921 | = decltype(std::declval<const common_iterator&>().operator->()); |
1922 | }; |
1923 | } // namespace __detail |
1924 | |
1925 | template<input_iterator _It, typename _Sent> |
1926 | struct iterator_traits<common_iterator<_It, _Sent>> |
1927 | { |
1928 | using iterator_concept = conditional_t<forward_iterator<_It>, |
1929 | forward_iterator_tag, input_iterator_tag>; |
1930 | using iterator_category = __detail::__clamp_iter_cat< |
1931 | typename iterator_traits<_It>::iterator_category, |
1932 | forward_iterator_tag, input_iterator_tag>; |
1933 | using value_type = iter_value_t<_It>; |
1934 | using difference_type = iter_difference_t<_It>; |
1935 | using pointer = typename __detail::__common_iter_ptr<_It, _Sent>::type; |
1936 | using reference = iter_reference_t<_It>; |
1937 | }; |
1938 | |
1939 | // [iterators.counted] Counted iterators |
1940 | |
1941 | /// An iterator adaptor that keeps track of the distance to the end. |
1942 | template<input_or_output_iterator _It> |
1943 | class counted_iterator |
1944 | { |
1945 | public: |
1946 | using iterator_type = _It; |
1947 | |
1948 | constexpr counted_iterator() = default; |
1949 | |
1950 | constexpr |
1951 | counted_iterator(_It __i, iter_difference_t<_It> __n) |
1952 | : _M_current(std::move(__i)), _M_length(__n) |
1953 | { __glibcxx_assert(__n >= 0); } |
1954 | |
1955 | template<typename _It2> |
1956 | requires convertible_to<const _It2&, _It> |
1957 | constexpr |
1958 | counted_iterator(const counted_iterator<_It2>& __x) |
1959 | : _M_current(__x._M_current), _M_length(__x._M_length) |
1960 | { } |
1961 | |
1962 | template<typename _It2> |
1963 | requires assignable_from<_It&, const _It2&> |
1964 | constexpr counted_iterator& |
1965 | operator=(const counted_iterator<_It2>& __x) |
1966 | { |
1967 | _M_current = __x._M_current; |
1968 | _M_length = __x._M_length; |
1969 | return *this; |
1970 | } |
1971 | |
1972 | constexpr _It |
1973 | base() const & |
1974 | noexcept(is_nothrow_copy_constructible_v<_It>) |
1975 | requires copy_constructible<_It> |
1976 | { return _M_current; } |
1977 | |
1978 | constexpr _It |
1979 | base() && |
1980 | noexcept(is_nothrow_move_constructible_v<_It>) |
1981 | { return std::move(_M_current); } |
1982 | |
1983 | constexpr iter_difference_t<_It> |
1984 | count() const noexcept { return _M_length; } |
1985 | |
1986 | constexpr decltype(auto) |
1987 | operator*() |
1988 | noexcept(noexcept(*_M_current)) |
1989 | { return *_M_current; } |
1990 | |
1991 | constexpr decltype(auto) |
1992 | operator*() const |
1993 | noexcept(noexcept(*_M_current)) |
1994 | requires __detail::__dereferenceable<const _It> |
1995 | { return *_M_current; } |
1996 | |
1997 | constexpr counted_iterator& |
1998 | operator++() |
1999 | { |
2000 | __glibcxx_assert(_M_length > 0); |
2001 | ++_M_current; |
2002 | --_M_length; |
2003 | return *this; |
2004 | } |
2005 | |
2006 | decltype(auto) |
2007 | operator++(int) |
2008 | { |
2009 | __glibcxx_assert(_M_length > 0); |
2010 | --_M_length; |
2011 | __trytry |
2012 | { |
2013 | return _M_current++; |
2014 | } __catch(...)catch(...) { |
2015 | ++_M_length; |
2016 | throw; |
2017 | } |
2018 | |
2019 | } |
2020 | |
2021 | constexpr counted_iterator |
2022 | operator++(int) requires forward_iterator<_It> |
2023 | { |
2024 | auto __tmp = *this; |
2025 | ++*this; |
2026 | return __tmp; |
2027 | } |
2028 | |
2029 | constexpr counted_iterator& |
2030 | operator--() requires bidirectional_iterator<_It> |
2031 | { |
2032 | --_M_current; |
2033 | ++_M_length; |
2034 | return *this; |
2035 | } |
2036 | |
2037 | constexpr counted_iterator |
2038 | operator--(int) requires bidirectional_iterator<_It> |
2039 | { |
2040 | auto __tmp = *this; |
2041 | --*this; |
2042 | return __tmp; |
2043 | } |
2044 | |
2045 | constexpr counted_iterator |
2046 | operator+(iter_difference_t<_It> __n) const |
2047 | requires random_access_iterator<_It> |
2048 | { return counted_iterator(_M_current + __n, _M_length - __n); } |
2049 | |
2050 | friend constexpr counted_iterator |
2051 | operator+(iter_difference_t<_It> __n, const counted_iterator& __x) |
2052 | requires random_access_iterator<_It> |
2053 | { return __x + __n; } |
2054 | |
2055 | constexpr counted_iterator& |
2056 | operator+=(iter_difference_t<_It> __n) |
2057 | requires random_access_iterator<_It> |
2058 | { |
2059 | __glibcxx_assert(__n <= _M_length); |
2060 | _M_current += __n; |
2061 | _M_length -= __n; |
2062 | return *this; |
2063 | } |
2064 | |
2065 | constexpr counted_iterator |
2066 | operator-(iter_difference_t<_It> __n) const |
2067 | requires random_access_iterator<_It> |
2068 | { return counted_iterator(_M_current - __n, _M_length + __n); } |
2069 | |
2070 | template<common_with<_It> _It2> |
2071 | friend constexpr iter_difference_t<_It2> |
2072 | operator-(const counted_iterator& __x, |
2073 | const counted_iterator<_It2>& __y) |
2074 | { return __y._M_length - __x._M_length; } |
2075 | |
2076 | friend constexpr iter_difference_t<_It> |
2077 | operator-(const counted_iterator& __x, default_sentinel_t) |
2078 | { return -__x._M_length; } |
2079 | |
2080 | friend constexpr iter_difference_t<_It> |
2081 | operator-(default_sentinel_t, const counted_iterator& __y) |
2082 | { return __y._M_length; } |
2083 | |
2084 | constexpr counted_iterator& |
2085 | operator-=(iter_difference_t<_It> __n) |
2086 | requires random_access_iterator<_It> |
2087 | { |
2088 | __glibcxx_assert(-__n <= _M_length); |
2089 | _M_current -= __n; |
2090 | _M_length += __n; |
2091 | return *this; |
2092 | } |
2093 | |
2094 | constexpr decltype(auto) |
2095 | operator[](iter_difference_t<_It> __n) const |
2096 | noexcept(noexcept(_M_current[__n])) |
2097 | requires random_access_iterator<_It> |
2098 | { |
2099 | __glibcxx_assert(__n < _M_length); |
2100 | return _M_current[__n]; |
2101 | } |
2102 | |
2103 | template<common_with<_It> _It2> |
2104 | friend constexpr bool |
2105 | operator==(const counted_iterator& __x, |
2106 | const counted_iterator<_It2>& __y) |
2107 | { return __x._M_length == __y._M_length; } |
2108 | |
2109 | friend constexpr bool |
2110 | operator==(const counted_iterator& __x, default_sentinel_t) |
2111 | { return __x._M_length == 0; } |
2112 | |
2113 | template<common_with<_It> _It2> |
2114 | friend constexpr strong_ordering |
2115 | operator<=>(const counted_iterator& __x, |
2116 | const counted_iterator<_It2>& __y) |
2117 | { return __y._M_length <=> __x._M_length; } |
2118 | |
2119 | friend constexpr iter_rvalue_reference_t<_It> |
2120 | iter_move(const counted_iterator& __i) |
2121 | noexcept(noexcept(ranges::iter_move(__i._M_current))) |
2122 | requires input_iterator<_It> |
2123 | { return ranges::iter_move(__i._M_current); } |
2124 | |
2125 | template<indirectly_swappable<_It> _It2> |
2126 | friend constexpr void |
2127 | iter_swap(const counted_iterator& __x, |
2128 | const counted_iterator<_It2>& __y) |
2129 | noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) |
2130 | { ranges::iter_swap(__x._M_current, __y._M_current); } |
2131 | |
2132 | private: |
2133 | template<input_or_output_iterator _It2> friend class counted_iterator; |
2134 | |
2135 | _It _M_current = _It(); |
2136 | iter_difference_t<_It> _M_length = 0; |
2137 | }; |
2138 | |
2139 | template<typename _It> |
2140 | struct incrementable_traits<counted_iterator<_It>> |
2141 | { |
2142 | using difference_type = iter_difference_t<_It>; |
2143 | }; |
2144 | |
2145 | template<input_iterator _It> |
2146 | struct iterator_traits<counted_iterator<_It>> : iterator_traits<_It> |
2147 | { |
2148 | using pointer = void; |
2149 | }; |
2150 | #endif // C++20 |
2151 | |
2152 | // @} group iterators |
2153 | |
2154 | template<typename _Iterator> |
2155 | auto |
2156 | __niter_base(move_iterator<_Iterator> __it) |
2157 | -> decltype(make_move_iterator(__niter_base(__it.base()))) |
2158 | { return make_move_iterator(__niter_base(__it.base())); } |
2159 | |
2160 | template<typename _Iterator> |
2161 | struct __is_move_iterator<move_iterator<_Iterator> > |
2162 | { |
2163 | enum { __value = 1 }; |
2164 | typedef __true_type __type; |
2165 | }; |
2166 | |
2167 | template<typename _Iterator> |
2168 | auto |
2169 | __miter_base(move_iterator<_Iterator> __it) |
2170 | -> decltype(__miter_base(__it.base())) |
2171 | { return __miter_base(__it.base()); } |
2172 | |
2173 | #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter)std::make_move_iterator(_Iter) std::make_move_iterator(_Iter) |
2174 | #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter)std::__make_move_if_noexcept_iterator(_Iter) \ |
2175 | std::__make_move_if_noexcept_iterator(_Iter) |
2176 | #else |
2177 | #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter)std::make_move_iterator(_Iter) (_Iter) |
2178 | #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter)std::__make_move_if_noexcept_iterator(_Iter) (_Iter) |
2179 | #endif // C++11 |
2180 | |
2181 | #if __cpp_deduction_guides201703L >= 201606 |
2182 | // These helper traits are used for deduction guides |
2183 | // of associative containers. |
2184 | template<typename _InputIterator> |
2185 | using __iter_key_t = remove_const_t< |
2186 | typename iterator_traits<_InputIterator>::value_type::first_type>; |
2187 | |
2188 | template<typename _InputIterator> |
2189 | using __iter_val_t = |
2190 | typename iterator_traits<_InputIterator>::value_type::second_type; |
2191 | |
2192 | template<typename _T1, typename _T2> |
2193 | struct pair; |
2194 | |
2195 | template<typename _InputIterator> |
2196 | using __iter_to_alloc_t = |
2197 | pair<add_const_t<__iter_key_t<_InputIterator>>, |
2198 | __iter_val_t<_InputIterator>>; |
2199 | #endif // __cpp_deduction_guides |
2200 | |
2201 | _GLIBCXX_END_NAMESPACE_VERSION |
2202 | } // namespace |
2203 | |
2204 | #ifdef _GLIBCXX_DEBUG |
2205 | # include <debug/stl_iterator.h> |
2206 | #endif |
2207 | |
2208 | #endif |
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 | |
75 | namespace 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; } |
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 |