Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooLinkedListIter.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * File: $Id: RooLinkedListIter.h,v 1.11 2007/05/11 09:11:30 verkerke Exp $
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 #ifndef ROO_LINKED_LIST_ITER
17 #define ROO_LINKED_LIST_ITER
18 
19 #include "TIterator.h"
20 #include "RooLinkedList.h"
21 
22 #include <memory>
23 #include <assert.h>
24 
25 /// Interface for RooFIter-compatible iterators
26 class GenericRooFIter
27 {
28  public:
29  /// Return next element or nullptr if at end.
30  virtual RooAbsArg * next() = 0;
31  virtual ~GenericRooFIter() {}
32 };
33 
34 ////////////////////////////////////////////////////////////////////////////////////////////
35 /// A one-time forward iterator working on RooLinkedList or RooAbsCollection.
36 /// This wrapper separates the interface visible to the outside from the actual
37 /// implementation of the iterator.
38 class RooFIter final
39 {
40  public:
41  RooFIter(std::unique_ptr<GenericRooFIter> && itImpl) : fIterImpl{std::move(itImpl)} {}
42  RooFIter(const RooFIter &) = delete;
43  RooFIter(RooFIter &&) = default;
44  RooFIter & operator=(const RooFIter &) = delete;
45  RooFIter & operator=(RooFIter &&) = default;
46 
47  /// Return next element or nullptr if at end.
48  RooAbsArg *next() {
49  return fIterImpl->next();
50  }
51 
52  private:
53  std::unique_ptr<GenericRooFIter> fIterImpl;
54 };
55 
56 ////////////////////////////////////////////////////////////////////////////////////////////
57 /// Implementation of the GenericRooFIter interface for the RooLinkedList
58 class RooFIterForLinkedList final : public GenericRooFIter
59 {
60  public:
61  RooFIterForLinkedList() {}
62  RooFIterForLinkedList(const RooLinkedList* list) : fPtr (list->_first) {}
63 
64  /// Return next element in collection
65  RooAbsArg *next() override {
66  if (!fPtr) return nullptr ;
67  TObject* arg = fPtr->_arg ;
68  fPtr = fPtr->_next;
69  return (RooAbsArg*) arg ;
70  }
71 
72  private:
73  const RooLinkedListElem * fPtr{nullptr}; //! Next link element
74 };
75 
76 
77 
78 
79 ////////////////////////////////////////////////////////////////////////////////////////////
80 /// TIterator and GenericRooFIter front end with STL back end.
81 ///
82 /// By default, this iterators counts, at which position the current element should be.
83 /// On request, it does an index access to the underlying collection, and returns the element.
84 /// This happens because the RooLinkedList, which used to be the default collection in RooFit,
85 /// will not invalidate iterators when inserting elements. Since the default is now an STL collection,
86 /// reallocations might invalidate the iterator.
87 ///
88 /// With an iterator that counts, only inserting before or at the iterator position will create problems.
89 /// deal with reallocations while iterating. Therefore, this iterator will also check that the last element
90 /// it was pointing to is the the current element when it is invoked again. This ensures that
91 /// inserting or removing before this iterator does not happen, which was possible with
92 /// the linked list iterators of RooFit.
93 /// When NDEBUG is defined, these checks will disappear.
94 /// \note This is a legacy iterator that only exists to not break old code. Use begin(), end() and
95 /// range-based for loops with RooArgList and RooArgSet.
96 template<class STLContainer>
97 class TIteratorToSTLInterface final : public TIterator , public GenericRooFIter {
98 public:
99 
100  TIteratorToSTLInterface(const STLContainer & container) :
101  TIterator(),
102  GenericRooFIter(),
103  fSTLContainer(container),
104  fIndex(0)
105 #ifdef NDEBUG
106  ,fCurrentElem{nullptr}
107 #else
108  ,fCurrentElem{fSTLContainer.empty() ? nullptr : fSTLContainer.front()}
109 #endif
110  {
111 
112  }
113 
114  TIterator & operator=(const TIterator &) override {
115  throw;
116  }
117 
118  const TCollection *GetCollection() const override {
119  return nullptr;
120  }
121 
122  RooAbsArg * next() override {
123  if (atEnd())
124  return nullptr;
125 #ifdef NDEBUG
126  return fSTLContainer[fIndex++];
127 #else
128  return nextChecked();
129 #endif
130  }
131 
132 
133  TObject * Next() override {
134  return static_cast<TObject*>(next());
135  }
136 
137  void Reset() override {
138  fIndex = 0;
139 #ifndef NDEBUG
140  fCurrentElem = fSTLContainer.empty() ? nullptr : fSTLContainer.front();
141 #endif
142 
143  }
144 
145  Bool_t operator!=(const TIterator & other) const override {
146  const auto * castedOther =
147  dynamic_cast<const TIteratorToSTLInterface<STLContainer>*>(&other);
148  return !castedOther || &fSTLContainer != &(castedOther->fSTLContainer)
149  || fIndex == castedOther->fIndex;
150  }
151 
152  TObject * operator*() const override {
153  if (atEnd())
154  return nullptr;
155 
156  #ifndef NDEBUG
157  assert(fCurrentElem == fSTLContainer[fIndex]);
158  #endif
159 
160  return static_cast<TObject*>(fSTLContainer[fIndex]);
161  }
162 
163 
164 private:
165  bool atEnd() const {
166  return fSTLContainer.empty()
167  || fIndex >= fSTLContainer.size();
168  }
169 
170 
171  RooAbsArg * nextChecked() {
172  RooAbsArg * ret = fSTLContainer.at(fIndex);
173  if (fCurrentElem != nullptr && ret != fCurrentElem) {
174  throw std::logic_error("A RooCollection should not be modified while iterating. "
175  "Only inserting at end is acceptable.");
176  }
177  fCurrentElem = ++fIndex < fSTLContainer.size() ? fSTLContainer[fIndex] : nullptr;
178 
179  return ret;
180  }
181 
182 
183  const STLContainer & fSTLContainer; //!
184  std::size_t fIndex; //!
185  const RooAbsArg * fCurrentElem; //!
186 };
187 
188 
189 
190 
191 ////////////////////////////////////////////////////////////////////////////////////////////
192 /// A wrapper around TIterator derivatives.
193 ///
194 /// It is called RooLinkedListIter because all classes assume that the RooAbsCollections use
195 /// a RooLinkedList, which is not true, any more.
196 /// The purpose of this wrapper is to act on the outside like a RooLinkedListIter, even though
197 /// the underlying implementation may work an a different container, like e.g.
198 /// an STL container. This is needed to not break user code that is using a RooLinkedList or
199 /// a RooAbsCollection.
200 ///
201 /// \note All code using this iterator as an iterator over a RooAbsCollection should move
202 /// to begin() and end() or range-based for loops. These are faster.
203 class RooLinkedListIter final : public TIterator {
204 
205  public:
206  RooLinkedListIter(std::shared_ptr<TIterator> iterImpl) :
207  fIterImpl{std::move(iterImpl)} {
208 
209  }
210 
211  RooLinkedListIter(const RooLinkedListIter &) = delete;
212  RooLinkedListIter(RooLinkedListIter &&) = default;
213  RooLinkedListIter & operator=(const RooLinkedListIter &) = delete;
214  RooLinkedListIter & operator=(RooLinkedListIter &&) = default;
215 
216  TIterator &operator=(const TIterator & other) override {fIterImpl->operator=(other); return *this;}
217  const TCollection *GetCollection() const override {return nullptr;}
218 
219  TObject * Next() override {return fIterImpl->Next();}
220  void Reset() override {fIterImpl->Reset();}
221  Bool_t operator!=(const TIterator & other) const override {return fIterImpl->operator!=(other);}
222  TObject * operator*() const override {return fIterImpl->operator*();}
223 
224  private:
225  std::shared_ptr<TIterator> fIterImpl; //!
226 };
227 
228 
229 ////////////////////////////////////////////////////////////////////////////////////////////
230 /// Implementation of the actual iterator on RooLinkedLists.
231 ///
232 class RooLinkedListIterImpl final : public TIterator {
233 public:
234 
235  RooLinkedListIterImpl() {
236  // coverity[UNINIT_CTOR]
237  } ;
238 
239 
240  RooLinkedListIterImpl(const RooLinkedList* list, Bool_t forward) :
241  TIterator(), _list(list), _ptr(forward ? _list->_first : _list->_last),
242  _forward(forward)
243  { }
244 
245  RooLinkedListIterImpl(const RooLinkedListIterImpl& other) :
246  TIterator(other), _list(other._list), _ptr(other._ptr),
247  _forward(other._forward)
248  {
249  // Copy constructor
250  }
251 
252  virtual ~RooLinkedListIterImpl() { }
253 
254  TIterator& operator=(const TIterator& other) {
255 
256  // Iterator assignment operator
257 
258  if (&other==this) return *this ;
259  const RooLinkedListIterImpl* iter = dynamic_cast<const RooLinkedListIterImpl*>(&other) ;
260  if (iter) {
261  _list = iter->_list ;
262  _ptr = iter->_ptr ;
263  _forward = iter->_forward ;
264  }
265  return *this ;
266  }
267 
268  virtual const TCollection *GetCollection() const {
269  // Dummy
270  return 0 ;
271  }
272 
273  virtual TObject *Next() {
274  // Return next element in collection
275  if (!_ptr) return 0 ;
276  TObject* arg = _ptr->_arg ;
277  _ptr = _forward ? _ptr->_next : _ptr->_prev ;
278  return arg ;
279  }
280 
281  TObject *NextNV() {
282  // Return next element in collection
283  if (!_ptr) return 0 ;
284  TObject* arg = _ptr->_arg ;
285  _ptr = _forward ? _ptr->_next : _ptr->_prev ;
286  return arg ;
287  }
288 
289 
290  virtual void Reset() {
291  // Return iterator to first element in collection
292  _ptr = _forward ? _list->_first : _list->_last ;
293  }
294 
295  bool operator!=(const TIterator &aIter) const {
296  const RooLinkedListIterImpl *iter(dynamic_cast<const RooLinkedListIterImpl*>(&aIter));
297  if (iter) return (_ptr != iter->_ptr);
298  return false; // for base class we don't implement a comparison
299  }
300 
301  bool operator!=(const RooLinkedListIterImpl &aIter) const {
302  return (_ptr != aIter._ptr);
303  }
304 
305  virtual TObject *operator*() const {
306  // Return element iterator points to
307  return (_ptr ? _ptr->_arg : nullptr);
308  }
309 
310 protected:
311  const RooLinkedList* _list ; //! Collection iterated over
312  const RooLinkedListElem* _ptr ; //! Next link element
313  Bool_t _forward ; //! Iterator direction
314 };
315 
316 
317 
318 
319 #endif