Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooAbsCollection.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
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 
17 /**
18 \file RooAbsCollection.cxx
19 \class RooAbsCollection
20 \ingroup Roofitcore
21 
22 RooAbsCollection is an abstract container object that can hold
23 multiple RooAbsArg objects. Collections are ordered and can
24 contain multiple objects of the same name, (but a derived
25 implementation can enforce unique names). The storage of objects is
26 implemented using the container denoted by RooAbsCollection::Storage_t.
27 **/
28 
29 #include "RooAbsCollection.h"
30 
31 #include "Riostream.h"
32 #include "TClass.h"
33 #include "TStopwatch.h"
34 #include "TRegexp.h"
35 #include "RooStreamParser.h"
36 #include "RooFormula.h"
37 #include "RooAbsRealLValue.h"
38 #include "RooAbsCategoryLValue.h"
39 #include "RooStringVar.h"
40 #include "RooTrace.h"
41 #include "RooArgList.h"
42 #include "RooLinkedListIter.h"
43 #include "RooCmdConfig.h"
44 #include "RooRealVar.h"
45 #include "RooGlobalFunc.h"
46 #include "RooMsgService.h"
47 #include <ROOT/RMakeUnique.hxx>
48 
49 #include <algorithm>
50 #include <iomanip>
51 
52 using std::endl;
53 using std::vector;
54 using std::string;
55 using std::ostream;
56 using std::cout;
57 
58 #if (__GNUC__==3&&__GNUC_MINOR__==2&&__GNUC_PATCHLEVEL__==3)
59 char* operator+( streampos&, char* );
60 #endif
61 
62 ClassImp(RooAbsCollection);
63  ;
64 
65 ////////////////////////////////////////////////////////////////////////////////
66 /// Default constructor
67 
68 RooAbsCollection::RooAbsCollection() :
69  _list(),
70  _ownCont(kFALSE),
71  _name(),
72  _allRRV(kTRUE)
73 {
74  _list.reserve(8);
75 }
76 
77 
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Empty collection constructor
81 
82 RooAbsCollection::RooAbsCollection(const char *name) :
83  _list(),
84  _ownCont(kFALSE),
85  _name(name),
86  _allRRV(kTRUE)
87 {
88  _list.reserve(8);
89 }
90 
91 
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Copy constructor. Note that a copy of a collection is always non-owning,
95 /// even the source collection is owning. To create an owning copy of
96 /// a collection (owning or not), use the snapshot() method.
97 
98 RooAbsCollection::RooAbsCollection(const RooAbsCollection& other, const char *name) :
99  TObject(other),
100  RooPrintable(other),
101  _list(),
102  _ownCont(kFALSE),
103  _name(name),
104  _allRRV(other._allRRV)
105 {
106  RooTrace::create(this) ;
107  if (!name) setName(other.GetName()) ;
108 
109  _list.reserve(other._list.size());
110 
111  for (auto item : other._list) {
112  add(*item);
113  }
114 }
115 
116 
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 /// Destructor
120 
121 RooAbsCollection::~RooAbsCollection()
122 {
123  // Delete all variables in our list if we own them
124  if(_ownCont){
125  safeDeleteList() ;
126  }
127 }
128 
129 
130 ////////////////////////////////////////////////////////////////////////////////
131 /// Examine client server dependencies in list and
132 /// delete contents in safe order: any client
133 /// is deleted before a server is deleted
134 
135 void RooAbsCollection::safeDeleteList()
136 {
137  // Handle trivial case here
138  if (_list.size() > 1) {
139  std::vector<RooAbsArg*> tmp;
140  tmp.reserve(_list.size());
141  do {
142  tmp.clear();
143  for (auto arg : _list) {
144  // Check if arg depends on remainder of list
145  if (!arg->dependsOn(*this, arg)) tmp.push_back(arg);
146  }
147 
148  // sort and uniquify, in case some elements occur more than once
149  std::sort(tmp.begin(), tmp.end());
150 
151  tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
152  // okay, can remove and delete what's in tmp
153  auto newEnd = _list.end();
154  for (auto item : tmp) {
155  newEnd = std::remove(_list.begin(), newEnd, item);
156  delete item;
157  }
158  _list.erase(newEnd, _list.end());
159  } while (!tmp.empty() && _list.size() > 1);
160 
161  // Check if there are any remaining elements
162  if (_list.size() > 1) {
163  coutW(ObjectHandling) << "RooAbsCollection::safeDeleteList(" << GetName()
164  << ") WARNING: unable to delete following elements in client-server order " ;
165  Print("1") ;
166  }
167  }
168 
169  // Built-in delete remaining elements
170  for (auto item : _list) {
171  delete item;
172  }
173  _list.clear();
174 }
175 
176 
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 /// Take a snap shot of current collection contents.
180 /// An owning collection is returned containing clones of
181 /// - Elements in this collection
182 /// - External dependents of all elements and recursively any dependents of those dependents
183 /// (if deepCopy flag is set)
184 ///
185 /// This is useful to save the values of variables or parameters. It doesn't require
186 /// deep copying if the parameters are direct members of the collection.
187 ///
188 /// If deepCopy is specified, the client-server links between the cloned
189 /// list elements and the cloned external dependents are reconnected to
190 /// each other, making the snapshot a completely self-contained entity.
191 ///
192 ///
193 
194 RooAbsCollection* RooAbsCollection::snapshot(Bool_t deepCopy) const
195 {
196  // First create empty list
197  TString snapName ;
198  if (TString(GetName()).Length()>0) {
199  snapName.Append("Snapshot of ") ;
200  snapName.Append(GetName()) ;
201  }
202  RooAbsCollection* output = (RooAbsCollection*) create(snapName.Data()) ;
203 
204  Bool_t error = snapshot(*output,deepCopy) ;
205  if (error) {
206  delete output ;
207  return 0 ;
208  }
209 
210  return output ;
211 }
212 
213 
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Take a snap shot of current collection contents:
217 /// An owning collection is returned containing clones of
218 ///
219 /// - Elements in this collection
220 /// - External dependents of all elements
221 /// and recursively any dependents of those dependents
222 /// (if deepCopy flag is set)
223 ///
224 /// If deepCopy is specified, the client-server links between the cloned
225 /// list elements and the cloned external dependents are reconnected to
226 /// each other, making the snapshot a completely self-contained entity.
227 ///
228 ///
229 
230 Bool_t RooAbsCollection::snapshot(RooAbsCollection& output, Bool_t deepCopy) const
231 {
232  // Copy contents
233  output.reserve(_list.size());
234  for (auto orig : _list) {
235  RooAbsArg *copy= (RooAbsArg*)orig->Clone();
236  output.add(*copy);
237  }
238 
239  // Add external dependents
240  Bool_t error(kFALSE) ;
241  if (deepCopy) {
242  // Recursively add clones of all servers
243  // Can only do index access because collection might reallocate when growing
244  for (Storage_t::size_type i = 0; i < output._list.size(); ++i) {
245  const auto var = output._list[i];
246  error |= output.addServerClonesToList(*var);
247  }
248  }
249 
250  // Handle eventual error conditions
251  if (error) {
252  coutE(ObjectHandling) << "RooAbsCollection::snapshot(): Errors occurred in deep clone process, snapshot not created" << endl ;
253  output._ownCont = kTRUE ;
254  return kTRUE ;
255  }
256 
257 
258 
259  // Redirect all server connections to internal list members
260  for (auto var : output) {
261  var->redirectServers(output,deepCopy);
262  }
263 
264 
265  // Transfer ownership of contents to list
266  output._ownCont = kTRUE ;
267  return kFALSE ;
268 }
269 
270 
271 
272 ////////////////////////////////////////////////////////////////////////////////
273 /// Add clones of servers of given argument to end of list
274 
275 Bool_t RooAbsCollection::addServerClonesToList(const RooAbsArg& var)
276 {
277  Bool_t ret(kFALSE) ;
278 
279  for (const auto server : var.servers()) {
280  RooAbsArg* tmp = find(*server) ;
281 
282  if (!tmp) {
283  RooAbsArg* serverClone = (RooAbsArg*)server->Clone() ;
284  serverClone->setAttribute("SnapShot_ExtRefClone") ;
285  _list.push_back(serverClone) ;
286  if (_allRRV && dynamic_cast<RooRealVar*>(serverClone)==0) {
287  _allRRV=kFALSE ;
288  }
289  ret |= addServerClonesToList(*server) ;
290  } else {
291 
292  }
293  }
294 
295  return ret ;
296 }
297 
298 
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 /// The assignment operator sets the value of any argument in our set
302 /// that also appears in the other set.
303 
304 RooAbsCollection &RooAbsCollection::operator=(const RooAbsCollection& other)
305 {
306  if (&other==this) return *this ;
307 
308  for (auto elem : _list) {
309  auto theirs = other.find(*elem);
310  if(!theirs) continue;
311  theirs->syncCache() ;
312  elem->copyCache(theirs) ;
313  elem->setAttribute("Constant",theirs->isConstant()) ;
314  }
315  return *this;
316 }
317 
318 
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 /// The assignment operator sets the value of any argument in our set
322 /// that also appears in the other set.
323 
324 RooAbsCollection &RooAbsCollection::assignValueOnly(const RooAbsCollection& other, Bool_t oneSafe)
325 {
326  if (&other==this) return *this ;
327 
328  // Short cut for 1 element assignment
329  if (getSize()==1 && getSize()==other.getSize() && oneSafe) {
330  other.first()->syncCache() ;
331  first()->copyCache(other.first(),kTRUE) ;
332  return *this ;
333  }
334 
335  for (auto elem : _list) {
336  auto theirs = other.find(*elem);
337  if(!theirs) continue;
338  theirs->syncCache() ;
339  elem->copyCache(theirs,kTRUE) ;
340  }
341  return *this;
342 }
343 
344 
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Functional equivalent of operator=() but assumes this and other collection
348 /// have same layout. Also no attributes are copied
349 
350 void RooAbsCollection::assignFast(const RooAbsCollection& other, Bool_t setValDirty)
351 {
352  if (&other==this) return ;
353  assert(_list.size() == other._list.size());
354 
355  auto iter2 = other._list.begin();
356  for (auto iter1 = _list.begin();
357  iter1 != _list.end() && iter2 != other._list.end();
358  ++iter1, ++iter2) {
359  // Identical size of iterators is documented assumption of method
360 
361  if (_allRRV) {
362  // All contents are known to be RooRealVars - fast version of assignment
363  auto ours = static_cast<RooRealVar*>(*iter1);
364  auto theirs = static_cast<RooRealVar*>(*iter2);
365  ours->copyCacheFast(*theirs,setValDirty);
366  } else {
367  (*iter2)->syncCache() ;
368  (*iter1)->copyCache(*iter2,kTRUE,setValDirty) ;
369  }
370  }
371 
372 }
373 
374 
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Add the specified argument to list. Returns kTRUE if successful, or
378 /// else kFALSE if a variable of the same name is already in the list.
379 /// This method can only be called on a list that is flagged as owning
380 /// all of its contents, or else on an empty list (which will force the
381 /// list into that mode).
382 
383 Bool_t RooAbsCollection::addOwned(RooAbsArg& var, Bool_t silent)
384 {
385  // check that we own our variables or else are empty
386  if(!_ownCont && (getSize() > 0) && !silent) {
387  coutE(ObjectHandling) << ClassName() << "::" << GetName() << "::addOwned: can only add to an owned list" << endl;
388  return kFALSE;
389  }
390  _ownCont= kTRUE;
391 
392  _list.push_back(&var);
393  if (_allRRV && dynamic_cast<RooRealVar*>(&var)==0) {
394  _allRRV=kFALSE ;
395  }
396 
397  return kTRUE;
398 }
399 
400 
401 
402 ////////////////////////////////////////////////////////////////////////////////
403 /// Add a clone of the specified argument to list. Returns a pointer to
404 /// the clone if successful, or else zero if a variable of the same name
405 /// is already in the list or the list does *not* own its variables (in
406 /// this case, try add() instead.) Calling addClone() on an empty list
407 /// forces it to take ownership of all its subsequent variables.
408 
409 RooAbsArg *RooAbsCollection::addClone(const RooAbsArg& var, Bool_t silent)
410 {
411  // check that we own our variables or else are empty
412  if(!_ownCont && (getSize() > 0) && !silent) {
413  coutE(ObjectHandling) << ClassName() << "::" << GetName() << "::addClone: can only add to an owned list" << endl;
414  return 0;
415  }
416  _ownCont= kTRUE;
417 
418  // add a pointer to a clone of this variable to our list (we now own it!)
419  auto clone2 = static_cast<RooAbsArg*>(var.Clone());
420  if (clone2) _list.push_back(clone2);
421  if (_allRRV && dynamic_cast<const RooRealVar*>(&var)==0) {
422  _allRRV=kFALSE ;
423  }
424 
425  return clone2;
426 }
427 
428 
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// Add the specified argument to list. Returns kTRUE if successful, or
432 /// else kFALSE if a variable of the same name is already in the list
433 /// or the list owns its variables (in this case, try addClone() or addOwned() instead).
434 
435 Bool_t RooAbsCollection::add(const RooAbsArg& var, Bool_t silent)
436 {
437  // check that this isn't a copy of a list
438  if(_ownCont && !silent) {
439  coutE(ObjectHandling) << ClassName() << "::" << GetName() << "::add: cannot add to an owned list" << endl;
440  return kFALSE;
441  }
442 
443  // add a pointer to this variable to our list (we don't own it!)
444  _list.push_back(const_cast<RooAbsArg*>(&var)); //FIXME
445  if (_allRRV && dynamic_cast<const RooRealVar*>(&var)==0) {
446  _allRRV=kFALSE ;
447  }
448  return kTRUE;
449 }
450 
451 
452 
453 ////////////////////////////////////////////////////////////////////////////////
454 /// Add a collection of arguments to this collection by calling add()
455 /// for each element in the source collection
456 
457 Bool_t RooAbsCollection::add(const RooAbsCollection& list, Bool_t silent)
458 {
459  Bool_t result(false) ;
460  _list.reserve(_list.size() + list._list.size());
461 
462  for (auto item : list._list) {
463  result |= add(*item,silent);
464  }
465 
466  return result;
467 }
468 
469 
470 
471 ////////////////////////////////////////////////////////////////////////////////
472 /// Add a collection of arguments to this collection by calling addOwned()
473 /// for each element in the source collection
474 
475 Bool_t RooAbsCollection::addOwned(const RooAbsCollection& list, Bool_t silent)
476 {
477  Bool_t result(false) ;
478  _list.reserve(_list.size() + list._list.size());
479 
480  for (auto item : list._list) {
481  result |= addOwned(*item, silent) ;
482  }
483 
484  return result;
485 }
486 
487 
488 
489 ////////////////////////////////////////////////////////////////////////////////
490 /// Add a collection of arguments to this collection by calling addOwned()
491 /// for each element in the source collection
492 
493 void RooAbsCollection::addClone(const RooAbsCollection& list, Bool_t silent)
494 {
495  _list.reserve(_list.size() + list._list.size());
496 
497  for (auto item : list._list) {
498  addClone(*item, silent);
499  }
500 }
501 
502 
503 
504 ////////////////////////////////////////////////////////////////////////////////
505 /// Replace any args in our set with args of the same name from the other set
506 /// and return kTRUE for success. Fails if this list is a copy of another.
507 
508 Bool_t RooAbsCollection::replace(const RooAbsCollection &other)
509 {
510  // check that this isn't a copy of a list
511  if(_ownCont) {
512  coutE(ObjectHandling) << "RooAbsCollection: cannot replace variables in a copied list" << endl;
513  return kFALSE;
514  }
515 
516  // loop over elements in the other list
517  for (const auto * arg : other._list) {
518  // do we have an arg of the same name in our set?
519  auto found = find(*arg);
520  if (found) replace(*found,*arg);
521  }
522  return kTRUE;
523 }
524 
525 
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 /// Replace var1 with var2 and return kTRUE for success. Fails if
529 /// this list is a copy of another, if var1 is not already in this set,
530 /// or if var2 is already in this set. var1 and var2 do not need to have
531 /// the same name.
532 
533 Bool_t RooAbsCollection::replace(const RooAbsArg& var1, const RooAbsArg& var2)
534 {
535  // check that this isn't a copy of a list
536  if(_ownCont) {
537  coutE(ObjectHandling) << "RooAbsCollection: cannot replace variables in a copied list" << endl;
538  return kFALSE;
539  }
540 
541  // is var1 already in this list?
542  const char *name= var1.GetName();
543  auto var1It = std::find(_list.begin(), _list.end(), &var1);
544 
545  if (var1It == _list.end()) {
546  coutE(ObjectHandling) << "RooAbsCollection: variable \"" << name << "\" is not in the list"
547  << " and cannot be replaced" << endl;
548  return kFALSE;
549  }
550 
551 
552  // is var2's name already in this list?
553  if (dynamic_cast<RooArgSet*>(this)) {
554  RooAbsArg *other = find(var2);
555  if(other != 0 && other != &var1) {
556  coutE(ObjectHandling) << "RooAbsCollection: cannot replace \"" << name
557  << "\" with already existing \"" << var2.GetName() << "\"" << endl;
558  return kFALSE;
559  }
560  }
561 
562  // replace var1 with var2
563  *var1It = const_cast<RooAbsArg*>(&var2); //FIXME
564 
565  if (_allRRV && dynamic_cast<const RooRealVar*>(&var2)==0) {
566  _allRRV=kFALSE ;
567  }
568 
569  return kTRUE;
570 }
571 
572 
573 
574 ////////////////////////////////////////////////////////////////////////////////
575 /// Remove the specified argument from our list. Return kFALSE if
576 /// the specified argument is not found in our list. An exact pointer
577 /// match is required, not just a match by name. A variable can be
578 /// removed from a copied list and will be deleted at the same time.
579 
580 Bool_t RooAbsCollection::remove(const RooAbsArg& var, Bool_t , Bool_t matchByNameOnly)
581 {
582  // is var already in this list?
583  const auto sizeBefore = _list.size();
584 
585  _list.erase(std::remove(_list.begin(), _list.end(), &var), _list.end());
586 
587  if (matchByNameOnly) {
588  const std::string name(var.GetName());
589  auto nameMatch = [&name](const RooAbsArg* elm) {
590  return elm->GetName() == name;
591  };
592  std::set<RooAbsArg*> toBeDeleted;
593 
594  if (_ownCont) {
595  std::for_each(_list.begin(), _list.end(), [&toBeDeleted, nameMatch](RooAbsArg* elm){
596  if (nameMatch(elm)) {
597  toBeDeleted.insert(elm);
598  }
599  });
600  }
601 
602  _list.erase(std::remove_if(_list.begin(), _list.end(), nameMatch), _list.end());
603 
604  for (auto arg : toBeDeleted)
605  delete arg;
606  }
607 
608  return sizeBefore != _list.size();
609 }
610 
611 
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// Remove each argument in the input list from our list using remove(const RooAbsArg&).
615 /// Return kFALSE in case of problems.
616 
617 Bool_t RooAbsCollection::remove(const RooAbsCollection& list, Bool_t silent, Bool_t matchByNameOnly)
618 {
619 
620  auto oldSize = _list.size();
621  for (auto item : list._list) {
622  remove(*item, silent, matchByNameOnly);
623  }
624 
625  return oldSize != _list.size();
626 }
627 
628 
629 
630 ////////////////////////////////////////////////////////////////////////////////
631 /// Remove all arguments from our set, deleting them if we own them.
632 /// This effectively restores our object to the state it would have
633 /// just after calling the RooAbsCollection(const char*) constructor.
634 
635 void RooAbsCollection::removeAll()
636 {
637  if(_ownCont) {
638  safeDeleteList() ;
639  _ownCont= kFALSE;
640  }
641  else {
642  _list.clear();
643  }
644 }
645 
646 
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 /// Set given attribute in each element of the collection by
650 /// calling each elements setAttribute() function.
651 
652 void RooAbsCollection::setAttribAll(const Text_t* name, Bool_t value)
653 {
654  for (auto arg : _list) {
655  arg->setAttribute(name, value);
656  }
657 }
658 
659 
660 
661 
662 ////////////////////////////////////////////////////////////////////////////////
663 /// Create a subset of the current collection, consisting only of those
664 /// elements with the specified attribute set. The caller is responsibe
665 /// for deleting the returned collection
666 
667 RooAbsCollection* RooAbsCollection::selectByAttrib(const char* name, Bool_t value) const
668 {
669  TString selName(GetName()) ;
670  selName.Append("_selection") ;
671  RooAbsCollection *sel = (RooAbsCollection*) create(selName.Data()) ;
672 
673  // Scan set contents for matching attribute
674  for (auto arg : _list) {
675  if (arg->getAttribute(name)==value)
676  sel->add(*arg) ;
677  }
678 
679  return sel ;
680 }
681 
682 
683 
684 
685 ////////////////////////////////////////////////////////////////////////////////
686 /// Create a subset of the current collection, consisting only of those
687 /// elements that are contained as well in the given reference collection.
688 /// The caller is responsible for deleting the returned collection
689 
690 RooAbsCollection* RooAbsCollection::selectCommon(const RooAbsCollection& refColl) const
691 {
692  // Create output set
693  TString selName(GetName()) ;
694  selName.Append("_selection") ;
695  RooAbsCollection *sel = (RooAbsCollection*) create(selName.Data()) ;
696 
697  // Scan set contents for matching attribute
698  for (auto arg : _list) {
699  if (refColl.find(*arg))
700  sel->add(*arg) ;
701  }
702 
703  return sel ;
704 }
705 
706 
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 /// Create a subset of the current collection, consisting only of those
710 /// elements with names matching the wildcard expressions in nameList,
711 /// supplied as a comma separated list
712 
713 RooAbsCollection* RooAbsCollection::selectByName(const char* nameList, Bool_t verbose) const
714 {
715  // Create output set
716  TString selName(GetName()) ;
717  selName.Append("_selection") ;
718  RooAbsCollection *sel = (RooAbsCollection*) create(selName.Data()) ;
719 
720  const size_t bufSize = strlen(nameList) + 1;
721  char* buf = new char[bufSize] ;
722  strlcpy(buf,nameList,bufSize) ;
723  char* wcExpr = strtok(buf,",") ;
724  while(wcExpr) {
725  TRegexp rexp(wcExpr,kTRUE) ;
726  if (verbose) {
727  cxcoutD(ObjectHandling) << "RooAbsCollection::selectByName(" << GetName() << ") processing expression '" << wcExpr << "'" << endl ;
728  }
729 
730  RooFIter iter = fwdIterator() ;
731  RooAbsArg* arg ;
732  while((arg=iter.next())) {
733  if (TString(arg->GetName()).Index(rexp)>=0) {
734  if (verbose) {
735  cxcoutD(ObjectHandling) << "RooAbsCollection::selectByName(" << GetName() << ") selected element " << arg->GetName() << endl ;
736  }
737  sel->add(*arg) ;
738  }
739  }
740  wcExpr = strtok(0,",") ;
741  }
742  delete[] buf ;
743 
744  return sel ;
745 }
746 
747 
748 
749 
750 ////////////////////////////////////////////////////////////////////////////////
751 /// Check if this and other collection have identically-named contents
752 
753 Bool_t RooAbsCollection::equals(const RooAbsCollection& otherColl) const
754 {
755  // First check equal length
756  if (getSize() != otherColl.getSize()) return kFALSE ;
757 
758  // Then check that each element of our list also occurs in the other list
759  auto compareByNamePtr = [](const RooAbsArg * left, const RooAbsArg * right) {
760  return left->namePtr() == right->namePtr();
761  };
762 
763  return std::is_permutation(_list.begin(), _list.end(),
764  otherColl._list.begin(),
765  compareByNamePtr);
766 }
767 
768 
769 
770 
771 ////////////////////////////////////////////////////////////////////////////////
772 /// Check if this and other collection have common entries
773 
774 Bool_t RooAbsCollection::overlaps(const RooAbsCollection& otherColl) const
775 {
776  for (auto arg : _list) {
777  if (otherColl.find(*arg)) {
778  return kTRUE ;
779  }
780  }
781  return kFALSE ;
782 }
783 
784 
785 
786 
787 ////////////////////////////////////////////////////////////////////////////////
788 /// Find object with given name in list. A null pointer
789 /// is returned if no object with the given name is found
790 
791 RooAbsArg * RooAbsCollection::find(const char *name) const
792 {
793  if (!name)
794  return nullptr;
795 
796  decltype(_list)::const_iterator item;
797 
798  if (_list.size() < 10) {
799  auto findByName = [name](const RooAbsArg * elm){
800  return strcmp(elm->GetName(), name) == 0;
801  };
802 
803  item = std::find_if(_list.begin(), _list.end(), findByName);
804  }
805  else {
806  const TNamed* nptr= RooNameReg::known(name);
807  if (!nptr) return nullptr;
808 
809  auto findByNamePtr = [nptr](const RooAbsArg* elm) {
810  return nptr == elm->namePtr();
811  };
812 
813  item = std::find_if(_list.begin(), _list.end(), findByNamePtr);
814  }
815 
816  return item != _list.end() ? *item : nullptr;
817 }
818 
819 
820 
821 ////////////////////////////////////////////////////////////////////////////////
822 /// Find object with given name in list. A null pointer
823 /// is returned if no object with the given name is found
824 
825 RooAbsArg * RooAbsCollection::find(const RooAbsArg& arg) const
826 {
827  const auto nptr = arg.namePtr();
828  auto findByNamePtr = [nptr](const RooAbsArg * listItem) {
829  return nptr == listItem->namePtr();
830  };
831 
832  auto item = std::find_if(_list.begin(), _list.end(), findByNamePtr);
833 
834  return item != _list.end() ? *item : nullptr;
835 }
836 
837 
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 /// Return comma separated list of contained object names as STL string
841 
842 string RooAbsCollection::contentsString() const
843 {
844  string retVal ;
845  for (auto arg : _list) {
846  retVal += arg->GetName();
847  retVal += ",";
848  }
849 
850  retVal.erase(retVal.end()-1);
851 
852  return retVal;
853 }
854 
855 
856 
857 ////////////////////////////////////////////////////////////////////////////////
858 /// Return collection name
859 
860 void RooAbsCollection::printName(ostream& os) const
861 {
862  os << GetName() ;
863 }
864 
865 
866 
867 ////////////////////////////////////////////////////////////////////////////////
868 /// Return collection title
869 
870 void RooAbsCollection::printTitle(ostream& os) const
871 {
872  os << GetTitle() ;
873 }
874 
875 
876 
877 ////////////////////////////////////////////////////////////////////////////////
878 /// Return collection class name
879 
880 void RooAbsCollection::printClassName(ostream& os) const
881 {
882  os << IsA()->GetName() ;
883 }
884 
885 
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 /// Define default RooPrinable print options for given Print() flag string
889 /// For inline printing only show value of objects, for default print show
890 /// name,class name value and extras of each object. In verbose mode
891 /// also add object adress, argument and title
892 
893 Int_t RooAbsCollection::defaultPrintContents(Option_t* opt) const
894 {
895  if (opt && TString(opt)=="I") {
896  return kValue ;
897  }
898  if (opt && TString(opt).Contains("v")) {
899  return kAddress|kName|kArgs|kClassName|kValue|kTitle|kExtras ;
900  }
901  return kName|kClassName|kValue ;
902 }
903 
904 
905 
906 
907 
908 ////////////////////////////////////////////////////////////////////////////////
909 /// Print value of collection, i.e. a comma separated list of contained
910 /// object names
911 
912 void RooAbsCollection::printValue(ostream& os) const
913 {
914  Bool_t first2(kTRUE) ;
915  os << "(" ;
916  for (auto arg : _list) {
917  if (!first2) {
918  os << "," ;
919  } else {
920  first2 = kFALSE ;
921  }
922  if (arg->IsA()->InheritsFrom(RooStringVar::Class())) {
923  os << '\'' << ((RooStringVar *)arg)->getVal() << '\'';
924  } else {
925  os << arg->GetName();
926  }
927  }
928  os << ")" ;
929 }
930 
931 
932 
933 ////////////////////////////////////////////////////////////////////////////////
934 /// Implement multiline printing of collection, one line for each contained object showing
935 /// the requested content
936 
937 void RooAbsCollection::printMultiline(ostream&os, Int_t contents, Bool_t /*verbose*/, TString indent) const
938 {
939  if (TString(GetName()).Length()>0 && (contents&kCollectionHeader)) {
940  os << indent << ClassName() << "::" << GetName() << ":" << (_ownCont?" (Owning contents)":"") << endl;
941  }
942 
943  TString deeper(indent);
944  deeper.Append(" ");
945 
946  // Adjust the width of the name field to fit the largest name, if requested
947  Int_t maxNameLen(1) ;
948  Int_t nameFieldLengthSaved = RooPrintable::_nameLength ;
949  if (nameFieldLengthSaved==0) {
950  for (auto next : _list) {
951  Int_t len = strlen(next->GetName()) ;
952  if (len>maxNameLen) maxNameLen = len ;
953  }
954  RooPrintable::nameFieldLength(maxNameLen+1) ;
955  }
956 
957  unsigned int idx = 0;
958  for (auto next : _list) {
959  os << indent << std::setw(3) << ++idx << ") ";
960  next->printStream(os,contents,kSingleLine,"");
961  }
962 
963  // Reset name field length, if modified
964  RooPrintable::nameFieldLength(nameFieldLengthSaved) ;
965 }
966 
967 
968 
969 ////////////////////////////////////////////////////////////////////////////////
970 /// Base contents dumper for debugging purposes
971 
972 void RooAbsCollection::dump() const
973 {
974  for (auto arg : _list) {
975  cout << arg << " " << arg->IsA()->GetName() << "::" << arg->GetName() << " (" << arg->GetTitle() << ")" << endl ;
976  }
977 }
978 
979 
980 
981 ////////////////////////////////////////////////////////////////////////////////
982 /// Output content of collection as LaTex table. By default a table with two columns is created: the left
983 /// column contains the name of each variable, the right column the value.
984 ///
985 /// The following optional named arguments can be used to modify the default behavior
986 /// <table>
987 /// <tr><th> Argument <th> Effect
988 /// <tr><td> `Columns(Int_t ncol)` <td> Fold table into multiple columns, i.e. ncol=3 will result in 3 x 2 = 6 total columns
989 /// <tr><td> `Sibling(const RooAbsCollection& other)` <td> Define sibling list.
990 /// The sibling list is assumed to have objects with the same
991 /// name in the same order. If this is not the case warnings will be printed. If a single
992 /// sibling list is specified, 3 columns will be output: the (common) name, the value of this
993 /// list and the value in the sibling list. Multiple sibling lists can be specified by
994 /// repeating the Sibling() command.
995 /// <tr><td> `Format(const char* str)` <td> Classic format string, provided for backward compatibility
996 /// <tr><td> `Format()` <td> Formatting arguments.
997 /// <table>
998 /// <tr><td> const char* what <td> Controls what is shown. "N" adds name, "E" adds error,
999 /// "A" shows asymmetric error, "U" shows unit, "H" hides the value
1000 /// <tr><td> `FixedPrecision(int n)` <td> Controls precision, set fixed number of digits
1001 /// <tr><td> `AutoPrecision(int n)` <td> Controls precision. Number of shown digits is calculated from error
1002 /// and n specified additional digits (1 is sensible default)
1003 /// <tr><td> `VerbatimName(Bool_t flag)` <td> Put variable name in a \\verb+ + clause.
1004 /// </table>
1005 /// <tr><td> `OutputFile(const char* fname)` <td> Send output to file with given name rather than standard output
1006 ///
1007 /// </table>
1008 ///
1009 /// Example use:
1010 /// ```
1011 /// list.printLatex(Columns(2), Format("NEU",AutoPrecision(1),VerbatimName()) );
1012 /// ```
1013 
1014 void RooAbsCollection::printLatex(const RooCmdArg& arg1, const RooCmdArg& arg2,
1015  const RooCmdArg& arg3, const RooCmdArg& arg4,
1016  const RooCmdArg& arg5, const RooCmdArg& arg6,
1017  const RooCmdArg& arg7, const RooCmdArg& arg8) const
1018 {
1019 
1020 
1021  // Define configuration for this method
1022  RooCmdConfig pc("RooAbsCollection::printLatex()") ;
1023  pc.defineInt("ncol","Columns",0,1) ;
1024  pc.defineString("outputFile","OutputFile",0,"") ;
1025  pc.defineString("format","Format",0,"NEYVU") ;
1026  pc.defineInt("sigDigit","Format",0,1) ;
1027  pc.defineObject("siblings","Sibling",0,0,kTRUE) ;
1028  pc.defineInt("dummy","FormatArgs",0,0) ;
1029  pc.defineMutex("Format","FormatArgs") ;
1030 
1031  // Stuff all arguments in a list
1032  RooLinkedList cmdList;
1033  cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
1034  cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
1035  cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
1036  cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
1037 
1038  // Process & check varargs
1039  pc.process(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
1040  if (!pc.ok(kTRUE)) {
1041  return ;
1042  }
1043 
1044  const char* outFile = pc.getString("outputFile") ;
1045  if (outFile && strlen(outFile)) {
1046  std::ofstream ofs(outFile) ;
1047  if (pc.hasProcessed("FormatArgs")) {
1048  RooCmdArg* formatCmd = static_cast<RooCmdArg*>(cmdList.FindObject("FormatArgs")) ;
1049  formatCmd->addArg(RooFit::LatexTableStyle()) ;
1050  printLatex(ofs,pc.getInt("ncol"),0,0,pc.getObjectList("siblings"),formatCmd) ;
1051  } else {
1052  printLatex(ofs,pc.getInt("ncol"),pc.getString("format"),pc.getInt("sigDigit"),pc.getObjectList("siblings")) ;
1053  }
1054  } else {
1055  if (pc.hasProcessed("FormatArgs")) {
1056  RooCmdArg* formatCmd = static_cast<RooCmdArg*>(cmdList.FindObject("FormatArgs")) ;
1057  formatCmd->addArg(RooFit::LatexTableStyle()) ;
1058  printLatex(cout,pc.getInt("ncol"),0,0,pc.getObjectList("siblings"),formatCmd) ;
1059  } else {
1060  printLatex(cout,pc.getInt("ncol"),pc.getString("format"),pc.getInt("sigDigit"),pc.getObjectList("siblings")) ;
1061  }
1062  }
1063 }
1064 
1065 
1066 
1067 
1068 ////////////////////////////////////////////////////////////////////////////////
1069 /// Internal implementation function of printLatex
1070 
1071 void RooAbsCollection::printLatex(ostream& ofs, Int_t ncol, const char* option, Int_t sigDigit, const RooLinkedList& siblingList, const RooCmdArg* formatCmd) const
1072 {
1073  // Count number of rows to print
1074  Int_t nrow = (Int_t) (getSize() / ncol + 0.99) ;
1075  Int_t i,j,k ;
1076 
1077  // Sibling list do not need to print their name as it is supposed to be the same
1078  TString sibOption ;
1079  RooCmdArg sibFormatCmd ;
1080  if (option) {
1081  sibOption = option ;
1082  sibOption.ReplaceAll("N","") ;
1083  sibOption.ReplaceAll("n","") ;
1084  } else {
1085  sibFormatCmd = *formatCmd ;
1086  TString tmp = formatCmd->_s[0] ;
1087  tmp.ReplaceAll("N","") ;
1088  tmp.ReplaceAll("n","") ;
1089  static char buf[100] ;
1090  strlcpy(buf,tmp.Data(),100) ;
1091  sibFormatCmd._s[0] = buf ;
1092  }
1093 
1094 
1095  // Make list of lists ;
1096  RooLinkedList listList ;
1097  listList.Add((RooAbsArg*)this) ;
1098  RooFIter sIter = siblingList.fwdIterator() ;
1099  RooAbsCollection* col ;
1100  while((col=(RooAbsCollection*)sIter.next())) {
1101  listList.Add(col) ;
1102  }
1103 
1104  RooLinkedList listListRRV ;
1105 
1106  // Make list of RRV-only components
1107  RooFIter lIter = listList.fwdIterator() ;
1108  RooArgList* prevList = 0 ;
1109  while((col=(RooAbsCollection*)lIter.next())) {
1110  RooArgList* list = new RooArgList ;
1111  RooFIter iter = col->fwdIterator() ;
1112  RooAbsArg* arg ;
1113  while((arg=iter.next())) {
1114 
1115  RooRealVar* rrv = dynamic_cast<RooRealVar*>(arg) ;
1116  if (rrv) {
1117  list->add(*rrv) ;
1118  } else {
1119  coutW(InputArguments) << "RooAbsCollection::printLatex: can only print RooRealVar in LateX, skipping non-RooRealVar object named "
1120  << arg->GetName() << endl ;
1121  }
1122  if (prevList && TString(rrv->GetName()).CompareTo(prevList->at(list->getSize()-1)->GetName())) {
1123  coutW(InputArguments) << "RooAbsCollection::printLatex: WARNING: naming and/or ordering of sibling list is different" << endl ;
1124  }
1125  }
1126  listListRRV.Add(list) ;
1127  if (prevList && list->getSize() != prevList->getSize()) {
1128  coutW(InputArguments) << "RooAbsCollection::printLatex: ERROR: sibling list(s) must have same length as self" << endl ;
1129  delete list ;
1130  listListRRV.Delete() ;
1131  return ;
1132  }
1133  prevList = list ;
1134  }
1135 
1136  // Construct table header
1137  Int_t nlist = listListRRV.GetSize() ;
1138  TString subheader = "l" ;
1139  for (k=0 ; k<nlist ; k++) subheader += "c" ;
1140 
1141  TString header = "\\begin{tabular}{" ;
1142  for (j=0 ; j<ncol ; j++) {
1143  if (j>0) header += "|" ;
1144  header += subheader ;
1145  }
1146  header += "}" ;
1147  ofs << header << endl ;
1148 
1149 
1150  // Print contents, delegating actual printing to RooRealVar::format()
1151  for (i=0 ; i<nrow ; i++) {
1152  for (j=0 ; j<ncol ; j++) {
1153  for (k=0 ; k<nlist ; k++) {
1154  RooRealVar* par = (RooRealVar*) ((RooArgList*)listListRRV.At(k))->at(i+j*nrow) ;
1155  if (par) {
1156  if (option) {
1157  TString* tmp = par->format(sigDigit,(k==0)?option:sibOption.Data()) ;
1158  ofs << *tmp ;
1159  delete tmp ;
1160  } else {
1161  TString* tmp = par->format((k==0)?*formatCmd:sibFormatCmd) ;
1162  ofs << *tmp ;
1163  delete tmp ;
1164  }
1165  }
1166  if (!(j==ncol-1 && k==nlist-1)) {
1167  ofs << " & " ;
1168  }
1169  }
1170  }
1171  ofs << "\\\\" << endl ;
1172  }
1173 
1174  ofs << "\\end{tabular}" << endl ;
1175  listListRRV.Delete() ;
1176 }
1177 
1178 
1179 
1180 
1181 ////////////////////////////////////////////////////////////////////////////////
1182 /// Return true if all contained object report to have their
1183 /// value inside the specified range
1184 
1185 Bool_t RooAbsCollection::allInRange(const char* rangeSpec) const
1186 {
1187  if (!rangeSpec) return kTRUE ;
1188 
1189  // Parse rangeSpec specification
1190  vector<string> cutVec ;
1191  if (rangeSpec && strlen(rangeSpec)>0) {
1192  if (strchr(rangeSpec,',')==0) {
1193  cutVec.push_back(rangeSpec) ;
1194  } else {
1195  const size_t bufSize = strlen(rangeSpec)+1;
1196  char* buf = new char[bufSize] ;
1197  strlcpy(buf,rangeSpec,bufSize) ;
1198  const char* oneRange = strtok(buf,",") ;
1199  while(oneRange) {
1200  cutVec.push_back(oneRange) ;
1201  oneRange = strtok(0,",") ;
1202  }
1203  delete[] buf ;
1204  }
1205  }
1206 
1207  // Apply range based selection criteria
1208  Bool_t selectByRange = kTRUE ;
1209  for (auto arg : _list) {
1210  Bool_t selectThisArg = kFALSE ;
1211  UInt_t icut ;
1212  for (icut=0 ; icut<cutVec.size() ; icut++) {
1213  if (arg->inRange(cutVec[icut].c_str())) {
1214  selectThisArg = kTRUE ;
1215  break ;
1216  }
1217  }
1218  if (!selectThisArg) {
1219  selectByRange = kFALSE ;
1220  break ;
1221  }
1222  }
1223 
1224  return selectByRange ;
1225 }
1226 
1227 
1228 
1229 ////////////////////////////////////////////////////////////////////////////////
1230 
1231 void RooAbsCollection::makeStructureTag()
1232 {
1233 }
1234 
1235 
1236 ////////////////////////////////////////////////////////////////////////////////
1237 
1238 void RooAbsCollection::makeTypedStructureTag()
1239 {
1240 }
1241 
1242 ////////////////////////////////////////////////////////////////////////////////
1243 /// If one of the TObject we have a referenced to is deleted, remove the
1244 /// reference.
1245 
1246 void RooAbsCollection::RecursiveRemove(TObject *obj)
1247 {
1248  if (obj && obj->InheritsFrom(RooAbsArg::Class())) remove(*(RooAbsArg*)obj,false,false);
1249 }
1250 
1251 ////////////////////////////////////////////////////////////////////////////////
1252 /// Sort collection using std::sort and name comparison
1253 
1254 void RooAbsCollection::sort(Bool_t reverse) {
1255  //Windows seems to need an implementation where two different std::sorts are written
1256  //down in two different blocks. Switching between the two comparators using a ternary
1257  //operator does not compile on windows, although the signature is identical.
1258  if (reverse) {
1259  const auto cmpReverse = [](const RooAbsArg * l, const RooAbsArg * r) {
1260  return strcmp(l->GetName(), r->GetName()) > 0;
1261  };
1262 
1263  std::sort(_list.begin(), _list.end(), cmpReverse);
1264  }
1265  else {
1266  const auto cmp = [](const RooAbsArg * l, const RooAbsArg * r) {
1267  return strcmp(l->GetName(), r->GetName()) < 0;
1268  };
1269 
1270  std::sort(_list.begin(), _list.end(), cmp);
1271  }
1272 }
1273 
1274 ////////////////////////////////////////////////////////////////////////////////
1275 /// Factory for legacy iterators.
1276 
1277 std::unique_ptr<RooAbsCollection::LegacyIterator_t> RooAbsCollection::makeLegacyIterator (bool forward) const {
1278  if (!forward)
1279  ccoutE(DataHandling) << "The legacy RooFit collection iterators don't support reverse iterations, any more. "
1280  << "Use begin() and end()" << endl;
1281  return std::make_unique<LegacyIterator_t>(_list);
1282 }
1283