Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RVec.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Enric Tejedor, Danilo Piparo CERN 04/2021
2// Implementation adapted from from llvm::SmallVector.
3// See /math/vecops/ARCHITECTURE.md for more information.
4
5/*************************************************************************
6 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RVEC
14#define ROOT_RVEC
15
16#if __cplusplus > 201402L
17#define R__RVEC_NODISCARD [[nodiscard]]
18#else
19#define R__RVEC_NODISCARD
20#endif
21
22#ifdef _WIN32
23 #ifndef M_PI
24 #ifndef _USE_MATH_DEFINES
25 #define _USE_MATH_DEFINES
26 #endif
27 #include <math.h> // for M_PI
28 // TODO once minimum standard is C++20: replace with std::numbers::pi and remove this codeblock
29 #undef _USE_MATH_DEFINES
30 #endif
31 #define _VECOPS_USE_EXTERN_TEMPLATES false
32#else
33 #define _VECOPS_USE_EXTERN_TEMPLATES true
34#endif
35
36#include <Rtypes.h> // R__CLING_PTRCHECK
37#include <TError.h> // R__ASSERT
38
39#include <algorithm>
40#include <cmath>
41#include <cstring>
42#include <iterator> // for std::make_move_iterator
43#include <limits> // for numeric_limits
44#include <memory> // uninitialized_value_construct
45#include <new>
46#include <numeric> // for inner_product
47#include <sstream>
48#include <stdexcept>
49#include <string>
50#include <tuple>
51#include <type_traits>
52#include <utility>
53#include <vector>
54
55#ifdef R__HAS_VDT
56#include <vdt/vdtMath.h>
57#endif
58
59
60namespace ROOT {
61
62namespace VecOps {
63template<typename T>
64class RVec;
65}
66
67namespace Internal {
68namespace VecOps {
69
70template<typename T>
72
73// clang-format off
74template <typename>
75struct IsRVec : std::false_type {};
76
77template <typename T>
78struct IsRVec<ROOT::VecOps::RVec<T>> : std::true_type {};
79// clang-format on
80
81constexpr bool All(const bool *vals, std::size_t size)
82{
83 for (auto i = 0u; i < size; ++i)
84 if (!vals[i])
85 return false;
86 return true;
87}
88
89template <typename... T>
90std::size_t GetVectorsSize(const std::string &id, const RVec<T> &... vs)
91{
92 constexpr const auto nArgs = sizeof...(T);
93 const std::size_t sizes[] = {vs.size()...};
94 if (nArgs > 1) {
95 for (auto i = 1UL; i < nArgs; i++) {
96 if (sizes[0] == sizes[i])
97 continue;
98 std::string msg(id);
99 msg += ": input RVec instances have different lengths!";
100 throw std::runtime_error(msg);
101 }
102 }
103 return sizes[0];
104}
105
106template <typename F, typename... RVecs>
107auto MapImpl(F &&f, RVecs &&... vs) -> RVec<decltype(f(vs[0]...))>
108{
109 const auto size = GetVectorsSize("Map", vs...);
110 RVec<decltype(f(vs[0]...))> ret(size);
111
112 for (auto i = 0UL; i < size; i++)
113 ret[i] = f(vs[i]...);
114
115 return ret;
116}
117
118template <typename Tuple_t, std::size_t... Is>
119auto MapFromTuple(Tuple_t &&t, std::index_sequence<Is...>)
120 -> decltype(MapImpl(std::get<std::tuple_size<Tuple_t>::value - 1>(t), std::get<Is>(t)...))
121{
122 constexpr const auto tupleSizeM1 = std::tuple_size<Tuple_t>::value - 1;
123 return MapImpl(std::get<tupleSizeM1>(t), std::get<Is>(t)...);
124}
125
126/// Return the next power of two (in 64-bits) that is strictly greater than A.
127/// Return zero on overflow.
128inline uint64_t NextPowerOf2(uint64_t A)
129{
130 A |= (A >> 1);
131 A |= (A >> 2);
132 A |= (A >> 4);
133 A |= (A >> 8);
134 A |= (A >> 16);
135 A |= (A >> 32);
136 return A + 1;
137}
138
139/// This is all the stuff common to all SmallVectors.
141public:
142 // This limits the maximum size of an RVec<char> to ~4GB but we don't expect this to ever be a problem,
143 // and we prefer the smaller Size_T to reduce the size of each RVec object.
144 using Size_T = int32_t;
145
146protected:
147 void *fBeginX;
148 /// Always >= 0.
149 // Type is signed only for consistency with fCapacity.
151 /// Always >= -1. fCapacity == -1 indicates the RVec is in "memory adoption" mode.
153
154 /// The maximum value of the Size_T used.
155 static constexpr size_t SizeTypeMax() { return std::numeric_limits<Size_T>::max(); }
156
157 SmallVectorBase() = delete;
158 SmallVectorBase(void *FirstEl, size_t TotalCapacity) : fBeginX(FirstEl), fCapacity(TotalCapacity) {}
159
160 /// This is an implementation of the grow() method which only works
161 /// on POD-like data types and is out of line to reduce code duplication.
162 /// This function will report a fatal error if it cannot increase capacity.
163 void grow_pod(void *FirstEl, size_t MinSize, size_t TSize);
164
165 /// Report that MinSize doesn't fit into this vector's size type. Throws
166 /// std::length_error or calls report_fatal_error.
167 static void report_size_overflow(size_t MinSize);
168 /// Report that this vector is already at maximum capacity. Throws
169 /// std::length_error or calls report_fatal_error.
170 static void report_at_maximum_capacity();
171
172 /// If false, the RVec is in "memory adoption" mode, i.e. it is acting as a view on a memory buffer it does not own.
173 bool Owns() const { return fCapacity != -1; }
174
175public:
176 size_t size() const { return fSize; }
177 size_t capacity() const noexcept { return Owns() ? fCapacity : fSize; }
178
179 R__RVEC_NODISCARD bool empty() const { return !fSize; }
180
181 /// Set the array size to \p N, which the current array must have enough
182 /// capacity for.
183 ///
184 /// This does not construct or destroy any elements in the vector.
185 ///
186 /// Clients can use this in conjunction with capacity() to write past the end
187 /// of the buffer when they know that more elements are available, and only
188 /// update the size later. This avoids the cost of value initializing elements
189 /// which will only be overwritten.
190 void set_size(size_t N)
191 {
192 if (N > capacity()) {
193 throw std::runtime_error("Setting size to a value greater than capacity.");
194 }
195 fSize = N;
196 }
197};
198
199/// Used to figure out the offset of the first element of an RVec
200template <class T>
202 alignas(SmallVectorBase) char Base[sizeof(SmallVectorBase)];
203 alignas(T) char FirstEl[sizeof(T)];
204};
205
206/// This is the part of SmallVectorTemplateBase which does not depend on whether the type T is a POD.
207template <typename T>
210
211 /// Find the address of the first element. For this pointer math to be valid
212 /// with small-size of 0 for T with lots of alignment, it's important that
213 /// SmallVectorStorage is properly-aligned even for small-size of 0.
214 void *getFirstEl() const
215 {
216 return const_cast<void *>(reinterpret_cast<const void *>(reinterpret_cast<const char *>(this) +
218 }
219 // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
220
221protected:
222 SmallVectorTemplateCommon(size_t Size) : Base(getFirstEl(), Size) {}
223
224 void grow_pod(size_t MinSize, size_t TSize) { Base::grow_pod(getFirstEl(), MinSize, TSize); }
225
226 /// Return true if this is a smallvector which has not had dynamic
227 /// memory allocated for it.
228 bool isSmall() const { return this->fBeginX == getFirstEl(); }
229
230 /// Put this vector in a state of being small.
232 {
233 this->fBeginX = getFirstEl();
234 // from the original LLVM implementation:
235 // FIXME: Setting fCapacity to 0 is suspect.
236 this->fSize = this->fCapacity = 0;
237 }
238
239public:
240 // note that fSize is a _signed_ integer, but we expose it as an unsigned integer for consistency with STL containers
241 // as well as backward-compatibility
242 using size_type = size_t;
243 using difference_type = ptrdiff_t;
244 using value_type = T;
245 using iterator = T *;
246 using const_iterator = const T *;
247
248 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
249 using reverse_iterator = std::reverse_iterator<iterator>;
250
251 using reference = T &;
252 using const_reference = const T &;
253 using pointer = T *;
254 using const_pointer = const T *;
255
256 using Base::capacity;
257 using Base::empty;
258 using Base::size;
259
260 // forward iterator creation methods.
261 iterator begin() noexcept { return (iterator)this->fBeginX; }
262 const_iterator begin() const noexcept { return (const_iterator)this->fBeginX; }
263 const_iterator cbegin() const noexcept { return (const_iterator)this->fBeginX; }
264 iterator end() noexcept { return begin() + size(); }
265 const_iterator end() const noexcept { return begin() + size(); }
266 const_iterator cend() const noexcept { return begin() + size(); }
267
268 // reverse iterator creation methods.
275
276 size_type size_in_bytes() const { return size() * sizeof(T); }
277 size_type max_size() const noexcept { return std::min(this->SizeTypeMax(), size_type(-1) / sizeof(T)); }
278
279 size_t capacity_in_bytes() const { return capacity() * sizeof(T); }
280
281 /// Return a pointer to the vector's buffer, even if empty().
282 pointer data() noexcept { return pointer(begin()); }
283 /// Return a pointer to the vector's buffer, even if empty().
285
287 {
288 if (empty()) {
289 throw std::runtime_error("`front` called on an empty RVec");
290 }
291 return begin()[0];
292 }
293
295 {
296 if (empty()) {
297 throw std::runtime_error("`front` called on an empty RVec");
298 }
299 return begin()[0];
300 }
301
303 {
304 if (empty()) {
305 throw std::runtime_error("`back` called on an empty RVec");
306 }
307 return end()[-1];
308 }
309
311 {
312 if (empty()) {
313 throw std::runtime_error("`back` called on an empty RVec");
314 }
315 return end()[-1];
316 }
317};
318
319/// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put
320/// method implementations that are designed to work with non-trivial T's.
321///
322/// We approximate is_trivially_copyable with trivial move/copy construction and
323/// trivial destruction. While the standard doesn't specify that you're allowed
324/// copy these types with memcpy, there is no way for the type to observe this.
325/// This catches the important case of std::pair<POD, POD>, which is not
326/// trivially assignable.
327template <typename T, bool = (std::is_trivially_copy_constructible<T>::value) &&
328 (std::is_trivially_move_constructible<T>::value) &&
329 std::is_trivially_destructible<T>::value>
331protected:
333
334 static void destroy_range(T *S, T *E)
335 {
336 while (S != E) {
337 --E;
338 E->~T();
339 }
340 }
341
342 /// Move the range [I, E) into the uninitialized memory starting with "Dest",
343 /// constructing elements as needed.
344 template <typename It1, typename It2>
346 {
347 std::uninitialized_copy(std::make_move_iterator(I), std::make_move_iterator(E), Dest);
348 }
349
350 /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
351 /// constructing elements as needed.
352 template <typename It1, typename It2>
354 {
355 std::uninitialized_copy(I, E, Dest);
356 }
357
358 /// Grow the allocated memory (without initializing new elements), doubling
359 /// the size of the allocated memory. Guarantees space for at least one more
360 /// element, or MinSize more elements if specified.
361 void grow(size_t MinSize = 0);
362
363public:
364 void push_back(const T &Elt)
365 {
366 if (R__unlikely(this->size() >= this->capacity()))
367 this->grow();
368 ::new ((void *)this->end()) T(Elt);
369 this->set_size(this->size() + 1);
370 }
371
372 void push_back(T &&Elt)
373 {
374 if (R__unlikely(this->size() >= this->capacity()))
375 this->grow();
376 ::new ((void *)this->end()) T(::std::move(Elt));
377 this->set_size(this->size() + 1);
378 }
379
380 void pop_back()
381 {
382 this->set_size(this->size() - 1);
383 this->end()->~T();
384 }
385};
386
387// Define this out-of-line to dissuade the C++ compiler from inlining it.
388template <typename T, bool TriviallyCopyable>
390{
391 // Ensure we can fit the new capacity.
392 // This is only going to be applicable when the capacity is 32 bit.
393 if (MinSize > this->SizeTypeMax())
394 this->report_size_overflow(MinSize);
395
396 // Ensure we can meet the guarantee of space for at least one more element.
397 // The above check alone will not catch the case where grow is called with a
398 // default MinSize of 0, but the current capacity cannot be increased.
399 // This is only going to be applicable when the capacity is 32 bit.
400 if (this->capacity() == this->SizeTypeMax())
401 this->report_at_maximum_capacity();
402
403 // Always grow, even from zero.
404 size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
405 NewCapacity = std::min(std::max(NewCapacity, MinSize), this->SizeTypeMax());
406 T *NewElts = static_cast<T *>(malloc(NewCapacity * sizeof(T)));
407 R__ASSERT(NewElts != nullptr);
408
409 // Move the elements over.
410 this->uninitialized_move(this->begin(), this->end(), NewElts);
411
412 if (this->Owns()) {
413 // Destroy the original elements.
414 destroy_range(this->begin(), this->end());
415
416 // If this wasn't grown from the inline copy, deallocate the old space.
417 if (!this->isSmall())
418 free(this->begin());
419 }
420
421 this->fBeginX = NewElts;
422 this->fCapacity = NewCapacity;
423}
424
425/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
426/// method implementations that are designed to work with trivially copyable
427/// T's. This allows using memcpy in place of copy/move construction and
428/// skipping destruction.
429template <typename T>
432
433protected:
435
436 // No need to do a destroy loop for POD's.
437 static void destroy_range(T *, T *) {}
438
439 /// Move the range [I, E) onto the uninitialized memory
440 /// starting with "Dest", constructing elements into it as needed.
441 template <typename It1, typename It2>
443 {
444 // Just do a copy.
445 uninitialized_copy(I, E, Dest);
446 }
447
448 /// Copy the range [I, E) onto the uninitialized memory
449 /// starting with "Dest", constructing elements into it as needed.
450 template <typename It1, typename It2>
452 {
453 // Arbitrary iterator types; just use the basic implementation.
454 std::uninitialized_copy(I, E, Dest);
455 }
456
457 /// Copy the range [I, E) onto the uninitialized memory
458 /// starting with "Dest", constructing elements into it as needed.
459 template <typename T1, typename T2>
461 T1 *I, T1 *E, T2 *Dest,
462 typename std::enable_if<std::is_same<typename std::remove_const<T1>::type, T2>::value>::type * = nullptr)
463 {
464 // Use memcpy for PODs iterated by pointers (which includes SmallVector
465 // iterators): std::uninitialized_copy optimizes to memmove, but we can
466 // use memcpy here. Note that I and E are iterators and thus might be
467 // invalid for memcpy if they are equal.
468 if (I != E)
469 memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
470 }
471
472 /// Double the size of the allocated memory, guaranteeing space for at
473 /// least one more element or MinSize if specified.
474 void grow(size_t MinSize = 0)
475 {
476 this->grow_pod(MinSize, sizeof(T));
477 }
478
479public:
482 using reference = typename SuperClass::reference;
483 using size_type = typename SuperClass::size_type;
484
485 void push_back(const T &Elt)
486 {
487 if (R__unlikely(this->size() >= this->capacity()))
488 this->grow();
489 memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T));
490 this->set_size(this->size() + 1);
491 }
492
493 void pop_back() { this->set_size(this->size() - 1); }
494};
495
496/// Storage for the SmallVector elements. This is specialized for the N=0 case
497/// to avoid allocating unnecessary storage.
498template <typename T, unsigned N>
500 alignas(T) char InlineElts[N * sizeof(T)]{};
501};
502
503/// We need the storage to be properly aligned even for small-size of 0 so that
504/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
505/// well-defined.
506template <typename T>
508};
509
510/// The size of the inline storage of an RVec.
511/// Our policy is to allocate at least 8 elements (or more if they all fit into one cacheline)
512/// unless the size of the buffer with 8 elements would be over a certain maximum size.
513template <typename T>
515private:
516 static constexpr std::size_t cacheLineSize = R__HARDWARE_INTERFERENCE_SIZE;
517 static constexpr unsigned elementsPerCacheLine = (cacheLineSize - sizeof(SmallVectorBase)) / sizeof(T);
518 static constexpr unsigned maxInlineByteSize = 1024;
519
520public:
521 static constexpr unsigned value =
522 elementsPerCacheLine >= 8 ? elementsPerCacheLine : (sizeof(T) * 8 > maxInlineByteSize ? 0 : 8);
523};
524
525// A C++14-compatible implementation of std::uninitialized_value_construct
526template <typename ForwardIt>
528{
529#if __cplusplus < 201703L
530 for (; first != last; ++first)
531 new (static_cast<void *>(std::addressof(*first))) typename std::iterator_traits<ForwardIt>::value_type();
532#else
533 std::uninitialized_value_construct(first, last);
534#endif
535}
536
537/// An unsafe function to reset the buffer for which this RVec is acting as a view.
538///
539/// \note This is a low-level method that _must_ be called on RVecs that are already non-owning:
540/// - it does not put the RVec in "non-owning mode" (fCapacity == -1)
541/// - it does not free any owned buffer
542template <typename T>
543void ResetView(RVec<T> &v, T* addr, std::size_t sz)
544{
545 v.fBeginX = addr;
546 v.fSize = sz;
547}
548
549} // namespace VecOps
550} // namespace Internal
551
552namespace Detail {
553namespace VecOps {
554
555/// This class consists of common code factored out of the SmallVector class to
556/// reduce code duplication based on the SmallVector 'N' template parameter.
557template <typename T>
560
561public:
566
567protected:
568 // Default ctor - Initialize to empty.
569 explicit RVecImpl(unsigned N) : ROOT::Internal::VecOps::SmallVectorTemplateBase<T>(N) {}
570
571public:
572 RVecImpl(const RVecImpl &) = delete;
573
575 {
576 // Subclass has already destructed this vector's elements.
577 // If this wasn't grown from the inline copy, deallocate the old space.
578 if (!this->isSmall() && this->Owns())
579 free(this->begin());
580 }
581
582 // also give up adopted memory if applicable
583 void clear()
584 {
585 if (this->Owns()) {
586 this->destroy_range(this->begin(), this->end());
587 this->fSize = 0;
588 } else {
589 this->resetToSmall();
590 }
591 }
592
594 {
595 if (N < this->size()) {
596 if (this->Owns())
597 this->destroy_range(this->begin() + N, this->end());
598 this->set_size(N);
599 } else if (N > this->size()) {
600 if (this->capacity() < N)
601 this->grow(N);
602 for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
603 new (&*I) T();
604 this->set_size(N);
605 }
606 }
607
608 void resize(size_type N, const T &NV)
609 {
610 if (N < this->size()) {
611 if (this->Owns())
612 this->destroy_range(this->begin() + N, this->end());
613 this->set_size(N);
614 } else if (N > this->size()) {
615 if (this->capacity() < N)
616 this->grow(N);
617 std::uninitialized_fill(this->end(), this->begin() + N, NV);
618 this->set_size(N);
619 }
620 }
621
623 {
624 if (this->capacity() < N)
625 this->grow(N);
626 }
627
628 void pop_back_n(size_type NumItems)
629 {
630 if (this->size() < NumItems) {
631 throw std::runtime_error("Popping back more elements than those available.");
632 }
633 if (this->Owns())
634 this->destroy_range(this->end() - NumItems, this->end());
635 this->set_size(this->size() - NumItems);
636 }
637
639 {
640 T Result = ::std::move(this->back());
641 this->pop_back();
642 return Result;
643 }
644
646
647 /// Add the specified range to the end of the SmallVector.
648 template <typename in_iter,
649 typename = typename std::enable_if<std::is_convertible<
650 typename std::iterator_traits<in_iter>::iterator_category, std::input_iterator_tag>::value>::type>
652 {
653 size_type NumInputs = std::distance(in_start, in_end);
654 if (NumInputs > this->capacity() - this->size())
655 this->grow(this->size() + NumInputs);
656
657 this->uninitialized_copy(in_start, in_end, this->end());
658 this->set_size(this->size() + NumInputs);
659 }
660
661 /// Append \p NumInputs copies of \p Elt to the end.
663 {
664 if (NumInputs > this->capacity() - this->size())
665 this->grow(this->size() + NumInputs);
666
667 std::uninitialized_fill_n(this->end(), NumInputs, Elt);
668 this->set_size(this->size() + NumInputs);
669 }
670
671 void append(std::initializer_list<T> IL) { append(IL.begin(), IL.end()); }
672
673 // from the original LLVM implementation:
674 // FIXME: Consider assigning over existing elements, rather than clearing &
675 // re-initializing them - for all assign(...) variants.
676
677 void assign(size_type NumElts, const T &Elt)
678 {
679 clear();
680 if (this->capacity() < NumElts)
681 this->grow(NumElts);
682 this->set_size(NumElts);
683 std::uninitialized_fill(this->begin(), this->end(), Elt);
684 }
685
686 template <typename in_iter,
687 typename = typename std::enable_if<std::is_convertible<
688 typename std::iterator_traits<in_iter>::iterator_category, std::input_iterator_tag>::value>::type>
690 {
691 clear();
692 append(in_start, in_end);
693 }
694
695 void assign(std::initializer_list<T> IL)
696 {
697 clear();
698 append(IL);
699 }
700
702 {
703 // Just cast away constness because this is a non-const member function.
704 iterator I = const_cast<iterator>(CI);
705
706 if (I < this->begin() || I >= this->end()) {
707 throw std::runtime_error("The iterator passed to `erase` is out of bounds.");
708 }
709
710 iterator N = I;
711 // Shift all elts down one.
712 std::move(I + 1, this->end(), I);
713 // Drop the last elt.
714 this->pop_back();
715 return (N);
716 }
717
719 {
720 // Just cast away constness because this is a non-const member function.
721 iterator S = const_cast<iterator>(CS);
722 iterator E = const_cast<iterator>(CE);
723
724 if (S < this->begin() || E > this->end() || S > E) {
725 throw std::runtime_error("Invalid start/end pair passed to `erase` (out of bounds or start > end).");
726 }
727
728 iterator N = S;
729 // Shift all elts down.
730 iterator I = std::move(E, this->end(), S);
731 // Drop the last elts.
732 if (this->Owns())
733 this->destroy_range(I, this->end());
734 this->set_size(I - this->begin());
735 return (N);
736 }
737
739 {
740 if (I == this->end()) { // Important special case for empty vector.
741 this->push_back(::std::move(Elt));
742 return this->end() - 1;
743 }
744
745 if (I < this->begin() || I > this->end()) {
746 throw std::runtime_error("The iterator passed to `insert` is out of bounds.");
747 }
748
749 if (this->size() >= this->capacity()) {
750 size_t EltNo = I - this->begin();
751 this->grow();
752 I = this->begin() + EltNo;
753 }
754
755 ::new ((void *)this->end()) T(::std::move(this->back()));
756 // Push everything else over.
757 std::move_backward(I, this->end() - 1, this->end());
758 this->set_size(this->size() + 1);
759
760 // If we just moved the element we're inserting, be sure to update
761 // the reference.
762 T *EltPtr = &Elt;
763 if (I <= EltPtr && EltPtr < this->end())
764 ++EltPtr;
765
766 *I = ::std::move(*EltPtr);
767 return I;
768 }
769
771 {
772 if (I == this->end()) { // Important special case for empty vector.
773 this->push_back(Elt);
774 return this->end() - 1;
775 }
776
777 if (I < this->begin() || I > this->end()) {
778 throw std::runtime_error("The iterator passed to `insert` is out of bounds.");
779 }
780
781 if (this->size() >= this->capacity()) {
782 size_t EltNo = I - this->begin();
783 this->grow();
784 I = this->begin() + EltNo;
785 }
786 ::new ((void *)this->end()) T(std::move(this->back()));
787 // Push everything else over.
788 std::move_backward(I, this->end() - 1, this->end());
789 this->set_size(this->size() + 1);
790
791 // If we just moved the element we're inserting, be sure to update
792 // the reference.
793 const T *EltPtr = &Elt;
794 if (I <= EltPtr && EltPtr < this->end())
795 ++EltPtr;
796
797 *I = *EltPtr;
798 return I;
799 }
800
802 {
803 // Convert iterator to elt# to avoid invalidating iterator when we reserve()
804 size_t InsertElt = I - this->begin();
805
806 if (I == this->end()) { // Important special case for empty vector.
807 append(NumToInsert, Elt);
808 return this->begin() + InsertElt;
809 }
810
811 if (I < this->begin() || I > this->end()) {
812 throw std::runtime_error("The iterator passed to `insert` is out of bounds.");
813 }
814
815 // Ensure there is enough space.
816 reserve(this->size() + NumToInsert);
817
818 // Uninvalidate the iterator.
819 I = this->begin() + InsertElt;
820
821 // If there are more elements between the insertion point and the end of the
822 // range than there are being inserted, we can use a simple approach to
823 // insertion. Since we already reserved space, we know that this won't
824 // reallocate the vector.
825 if (size_t(this->end() - I) >= NumToInsert) {
826 T *OldEnd = this->end();
827 append(std::move_iterator<iterator>(this->end() - NumToInsert), std::move_iterator<iterator>(this->end()));
828
829 // Copy the existing elements that get replaced.
830 std::move_backward(I, OldEnd - NumToInsert, OldEnd);
831
832 std::fill_n(I, NumToInsert, Elt);
833 return I;
834 }
835
836 // Otherwise, we're inserting more elements than exist already, and we're
837 // not inserting at the end.
838
839 // Move over the elements that we're about to overwrite.
840 T *OldEnd = this->end();
841 this->set_size(this->size() + NumToInsert);
842 size_t NumOverwritten = OldEnd - I;
843 this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
844
845 // Replace the overwritten part.
846 std::fill_n(I, NumOverwritten, Elt);
847
848 // Insert the non-overwritten middle part.
849 std::uninitialized_fill_n(OldEnd, NumToInsert - NumOverwritten, Elt);
850 return I;
851 }
852
853 template <typename ItTy,
854 typename = typename std::enable_if<std::is_convertible<
855 typename std::iterator_traits<ItTy>::iterator_category, std::input_iterator_tag>::value>::type>
857 {
858 // Convert iterator to elt# to avoid invalidating iterator when we reserve()
859 size_t InsertElt = I - this->begin();
860
861 if (I == this->end()) { // Important special case for empty vector.
862 append(From, To);
863 return this->begin() + InsertElt;
864 }
865
866 if (I < this->begin() || I > this->end()) {
867 throw std::runtime_error("The iterator passed to `insert` is out of bounds.");
868 }
869
870 size_t NumToInsert = std::distance(From, To);
871
872 // Ensure there is enough space.
873 reserve(this->size() + NumToInsert);
874
875 // Uninvalidate the iterator.
876 I = this->begin() + InsertElt;
877
878 // If there are more elements between the insertion point and the end of the
879 // range than there are being inserted, we can use a simple approach to
880 // insertion. Since we already reserved space, we know that this won't
881 // reallocate the vector.
882 if (size_t(this->end() - I) >= NumToInsert) {
883 T *OldEnd = this->end();
884 append(std::move_iterator<iterator>(this->end() - NumToInsert), std::move_iterator<iterator>(this->end()));
885
886 // Copy the existing elements that get replaced.
887 std::move_backward(I, OldEnd - NumToInsert, OldEnd);
888
889 std::copy(From, To, I);
890 return I;
891 }
892
893 // Otherwise, we're inserting more elements than exist already, and we're
894 // not inserting at the end.
895
896 // Move over the elements that we're about to overwrite.
897 T *OldEnd = this->end();
898 this->set_size(this->size() + NumToInsert);
899 size_t NumOverwritten = OldEnd - I;
900 this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
901
902 // Replace the overwritten part.
903 for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
904 *J = *From;
905 ++J;
906 ++From;
907 }
908
909 // Insert the non-overwritten middle part.
910 this->uninitialized_copy(From, To, OldEnd);
911 return I;
912 }
913
914 void insert(iterator I, std::initializer_list<T> IL) { insert(I, IL.begin(), IL.end()); }
915
916 template <typename... ArgTypes>
918 {
919 if (R__unlikely(this->size() >= this->capacity()))
920 this->grow();
921 ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
922 this->set_size(this->size() + 1);
923 return this->back();
924 }
925
927
929};
930
931template <typename T>
933{
934 if (this == &RHS)
935 return;
936
937 // We can only avoid copying elements if neither vector is small.
938 if (!this->isSmall() && !RHS.isSmall()) {
939 std::swap(this->fBeginX, RHS.fBeginX);
940 std::swap(this->fSize, RHS.fSize);
941 std::swap(this->fCapacity, RHS.fCapacity);
942 return;
943 }
944
945 // This block handles the swap of a small and a non-owning vector
946 // It is more efficient to first move the non-owning vector, hence the 2 cases
947 if (this->isSmall() && !RHS.Owns()) { // the right vector is non-owning
948 RVecImpl<T> temp(0);
949 temp = std::move(RHS);
950 RHS = std::move(*this);
951 *this = std::move(temp);
952 return;
953 } else if (RHS.isSmall() && !this->Owns()) { // the left vector is non-owning
954 RVecImpl<T> temp(0);
955 temp = std::move(*this);
956 *this = std::move(RHS);
957 RHS = std::move(temp);
958 return;
959 }
960
961 if (RHS.size() > this->capacity())
962 this->grow(RHS.size());
963 if (this->size() > RHS.capacity())
964 RHS.grow(this->size());
965
966 // Swap the shared elements.
967 size_t NumShared = this->size();
968 if (NumShared > RHS.size())
969 NumShared = RHS.size();
970 for (size_type i = 0; i != NumShared; ++i)
971 std::iter_swap(this->begin() + i, RHS.begin() + i);
972
973 // Copy over the extra elts.
974 if (this->size() > RHS.size()) {
975 size_t EltDiff = this->size() - RHS.size();
976 this->uninitialized_copy(this->begin() + NumShared, this->end(), RHS.end());
977 RHS.set_size(RHS.size() + EltDiff);
978 if (this->Owns())
979 this->destroy_range(this->begin() + NumShared, this->end());
980 this->set_size(NumShared);
981 } else if (RHS.size() > this->size()) {
982 size_t EltDiff = RHS.size() - this->size();
983 this->uninitialized_copy(RHS.begin() + NumShared, RHS.end(), this->end());
984 this->set_size(this->size() + EltDiff);
985 if (RHS.Owns())
986 this->destroy_range(RHS.begin() + NumShared, RHS.end());
987 RHS.set_size(NumShared);
988 }
989}
990
991template <typename T>
993{
994 // Avoid self-assignment.
995 if (this == &RHS)
996 return *this;
997
998 // If we already have sufficient space, assign the common elements, then
999 // destroy any excess.
1000 size_t RHSSize = RHS.size();
1001 size_t CurSize = this->size();
1002 if (CurSize >= RHSSize) {
1003 // Assign common elements.
1005 if (RHSSize)
1006 NewEnd = std::copy(RHS.begin(), RHS.begin() + RHSSize, this->begin());
1007 else
1008 NewEnd = this->begin();
1009
1010 // Destroy excess elements.
1011 if (this->Owns())
1012 this->destroy_range(NewEnd, this->end());
1013
1014 // Trim.
1015 this->set_size(RHSSize);
1016 return *this;
1017 }
1018
1019 // If we have to grow to have enough elements, destroy the current elements.
1020 // This allows us to avoid copying them during the grow.
1021 // From the original LLVM implementation:
1022 // FIXME: don't do this if they're efficiently moveable.
1023 if (this->capacity() < RHSSize) {
1024 if (this->Owns()) {
1025 // Destroy current elements.
1026 this->destroy_range(this->begin(), this->end());
1027 }
1028 this->set_size(0);
1029 CurSize = 0;
1030 this->grow(RHSSize);
1031 } else if (CurSize) {
1032 // Otherwise, use assignment for the already-constructed elements.
1033 std::copy(RHS.begin(), RHS.begin() + CurSize, this->begin());
1034 }
1035
1036 // Copy construct the new elements in place.
1037 this->uninitialized_copy(RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
1038
1039 // Set end.
1040 this->set_size(RHSSize);
1041 return *this;
1042}
1043
1044template <typename T>
1046{
1047 // Avoid self-assignment.
1048 if (this == &RHS)
1049 return *this;
1050
1051 // If the RHS isn't small, clear this vector and then steal its buffer.
1052 if (!RHS.isSmall()) {
1053 if (this->Owns()) {
1054 this->destroy_range(this->begin(), this->end());
1055 if (!this->isSmall())
1056 free(this->begin());
1057 }
1058 this->fBeginX = RHS.fBeginX;
1059 this->fSize = RHS.fSize;
1060 this->fCapacity = RHS.fCapacity;
1061 RHS.resetToSmall();
1062 return *this;
1063 }
1064
1065 // If we already have sufficient space, assign the common elements, then
1066 // destroy any excess.
1067 size_t RHSSize = RHS.size();
1068 size_t CurSize = this->size();
1069 if (CurSize >= RHSSize) {
1070 // Assign common elements.
1071 iterator NewEnd = this->begin();
1072 if (RHSSize)
1073 NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
1074
1075 // Destroy excess elements and trim the bounds.
1076 if (this->Owns())
1077 this->destroy_range(NewEnd, this->end());
1078 this->set_size(RHSSize);
1079
1080 // Clear the RHS.
1081 RHS.clear();
1082
1083 return *this;
1084 }
1085
1086 // If we have to grow to have enough elements, destroy the current elements.
1087 // This allows us to avoid copying them during the grow.
1088 // From the original LLVM implementation:
1089 // FIXME: this may not actually make any sense if we can efficiently move
1090 // elements.
1091 if (this->capacity() < RHSSize) {
1092 if (this->Owns()) {
1093 // Destroy current elements.
1094 this->destroy_range(this->begin(), this->end());
1095 }
1096 this->set_size(0);
1097 CurSize = 0;
1098 this->grow(RHSSize);
1099 } else if (CurSize) {
1100 // Otherwise, use assignment for the already-constructed elements.
1101 std::move(RHS.begin(), RHS.begin() + CurSize, this->begin());
1102 }
1103
1104 // Move-construct the new elements in place.
1105 this->uninitialized_move(RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
1106
1107 // Set end.
1108 this->set_size(RHSSize);
1109
1110 RHS.clear();
1111 return *this;
1112}
1113
1114template <typename T>
1116{
1117 return v.isSmall();
1118}
1119
1120template <typename T>
1122{
1123 return !v.Owns();
1124}
1125
1126} // namespace VecOps
1127} // namespace Detail
1128
1129namespace VecOps {
1130// Note that we open here with @{ the Doxygen group vecops and it is
1131// closed again at the end of the C++ namespace VecOps
1132/**
1133 * \defgroup vecops VecOps
1134 * A "std::vector"-like collection of values implementing handy operation to analyse them
1135 * @{
1136*/
1137
1138// From the original SmallVector code:
1139// This is a 'vector' (really, a variable-sized array), optimized
1140// for the case when the array is small. It contains some number of elements
1141// in-place, which allows it to avoid heap allocation when the actual number of
1142// elements is below that threshold. This allows normal "small" cases to be
1143// fast without losing generality for large inputs.
1144//
1145// Note that this does not attempt to be exception safe.
1146
1147template <typename T, unsigned int N>
1149public:
1150 RVecN() : Detail::VecOps::RVecImpl<T>(N) {}
1151
1153 {
1154 if (this->Owns()) {
1155 // Destroy the constructed elements in the vector.
1156 this->destroy_range(this->begin(), this->end());
1157 }
1158 }
1159
1160 explicit RVecN(size_t Size, const T &Value) : Detail::VecOps::RVecImpl<T>(N) { this->assign(Size, Value); }
1161
1162 explicit RVecN(size_t Size) : Detail::VecOps::RVecImpl<T>(N)
1163 {
1164 if (Size > N)
1165 this->grow(Size);
1166 this->fSize = Size;
1167 ROOT::Internal::VecOps::UninitializedValueConstruct(this->begin(), this->end());
1168 }
1169
1170 template <typename ItTy,
1171 typename = typename std::enable_if<std::is_convertible<
1172 typename std::iterator_traits<ItTy>::iterator_category, std::input_iterator_tag>::value>::type>
1173 RVecN(ItTy S, ItTy E) : Detail::VecOps::RVecImpl<T>(N)
1174 {
1175 this->append(S, E);
1176 }
1177
1178 RVecN(std::initializer_list<T> IL) : Detail::VecOps::RVecImpl<T>(N) { this->assign(IL); }
1179
1180 RVecN(const RVecN &RHS) : Detail::VecOps::RVecImpl<T>(N)
1181 {
1182 if (!RHS.empty())
1184 }
1185
1187 {
1189 return *this;
1190 }
1191
1192 RVecN(RVecN &&RHS) : Detail::VecOps::RVecImpl<T>(N)
1193 {
1194 if (!RHS.empty())
1196 }
1197
1198 RVecN(Detail::VecOps::RVecImpl<T> &&RHS) : Detail::VecOps::RVecImpl<T>(N)
1199 {
1200 if (!RHS.empty())
1202 }
1203
1204 RVecN(const std::vector<T> &RHS) : RVecN(RHS.begin(), RHS.end()) {}
1205
1207 {
1209 return *this;
1210 }
1211
1212 RVecN(T* p, size_t n) : Detail::VecOps::RVecImpl<T>(N)
1213 {
1214 this->fBeginX = p;
1215 this->fSize = n;
1216 this->fCapacity = -1;
1217 }
1218
1220 {
1222 return *this;
1223 }
1224
1225 RVecN &operator=(std::initializer_list<T> IL)
1226 {
1227 this->assign(IL);
1228 return *this;
1229 }
1230
1237
1239 {
1240 return begin()[idx];
1241 }
1242
1244 {
1245 return begin()[idx];
1246 }
1247
1250 {
1251 const size_type n = conds.size();
1252
1253 if (n != this->size()) {
1254 std::string msg = "Cannot index RVecN of size " + std::to_string(this->size()) +
1255 " with condition vector of different size (" + std::to_string(n) + ").";
1256 throw std::runtime_error(msg);
1257 }
1258
1259 size_type n_true = 0ull;
1260 for (auto c : conds)
1261 n_true += c; // relies on bool -> int conversion, faster than branching
1262
1263 RVecN ret;
1264 ret.reserve(n_true);
1265 for (size_type i = 0u; i < n; ++i) {
1266 if (conds[i]) {
1267 ret.push_back(this->operator[](i));
1268 }
1269 }
1270 return ret;
1271 }
1272
1273 // conversion
1275 operator RVecN<U, M>() const
1276 {
1277 return RVecN<U, M>(this->begin(), this->end());
1278 }
1279
1281 {
1282 if (pos >= size_type(this->fSize)) {
1283 std::string msg = "RVecN::at: size is " + std::to_string(this->fSize) + " but out-of-bounds index " +
1284 std::to_string(pos) + " was requested.";
1285 throw std::out_of_range(msg);
1286 }
1287 return this->operator[](pos);
1288 }
1289
1291 {
1292 if (pos >= size_type(this->fSize)) {
1293 std::string msg = "RVecN::at: size is " + std::to_string(this->fSize) + " but out-of-bounds index " +
1294 std::to_string(pos) + " was requested.";
1295 throw std::out_of_range(msg);
1296 }
1297 return this->operator[](pos);
1298 }
1299
1300 /// No exception thrown. The user specifies the desired value in case the RVecN is shorter than `pos`.
1302 {
1303 if (pos >= size_type(this->fSize))
1304 return fallback;
1305 return this->operator[](pos);
1306 }
1307
1308 /// No exception thrown. The user specifies the desired value in case the RVecN is shorter than `pos`.
1310 {
1311 if (pos >= size_type(this->fSize))
1312 return fallback;
1313 return this->operator[](pos);
1314 }
1315};
1316
1317// clang-format off
1318/**
1319\class ROOT::VecOps::RVec
1320\brief A "std::vector"-like collection of values implementing handy operation to analyse them
1321\tparam T The type of the contained objects
1322
1323A RVec is a container designed to make analysis of values' collections fast and easy.
1324Its storage is contiguous in memory and its interface is designed such to resemble to the one
1325of the stl vector. In addition the interface features methods and
1326[external functions](https://root.cern/doc/master/namespaceROOT_1_1VecOps.html) to ease the manipulation and analysis
1327of the data in the RVec.
1328
1329\note ROOT::VecOps::RVec can also be spelled simply ROOT::RVec. Shorthand aliases such as ROOT::RVecI or ROOT::RVecD
1330are also available as template instantiations of RVec of fundamental types. The full list of available aliases:
1331- RVecB (`bool`)
1332- RVecC (`char`)
1333- RVecD (`double`)
1334- RVecF (`float`)
1335- RVecI (`int`)
1336- RVecL (`long`)
1337- RVecLL (`long long`)
1338- RVecU (`unsigned`)
1339- RVecUL (`unsigned long`)
1340- RVecULL (`unsigned long long`)
1341
1342\note RVec does not attempt to be exception safe. Exceptions thrown by element constructors during insertions, swaps or
1343other operations will be propagated potentially leaving the RVec object in an invalid state.
1344
1345\note RVec methods (e.g. `at` or `size`) follow the STL naming convention instead of the ROOT naming convention in order
1346to make RVec a drop-in replacement for `std::vector`.
1347
1348\htmlonly
1349<a href="https://doi.org/10.5281/zenodo.1253756"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.1253756.svg" alt="DOI"></a>
1350\endhtmlonly
1351
1352## Table of Contents
1353- [Example](\ref example)
1354- [Arithmetic operations, logical operations and mathematical functions](\ref operationsandfunctions)
1355- [Owning and adopting memory](\ref owningandadoptingmemory)
1356- [Sorting and manipulation of indices](\ref sorting)
1357- [Usage in combination with RDataFrame](\ref usagetdataframe)
1358- [Reference for the RVec class](\ref RVecdoxyref)
1359- [Reference for RVec helper functions](https://root.cern/doc/master/namespaceROOT_1_1VecOps.html)
1360
1361\anchor example
1362## Example
1363Suppose to have an event featuring a collection of muons with a certain pseudorapidity,
1364momentum and charge, e.g.:
1365~~~{.cpp}
1366std::vector<short> mu_charge {1, 1, -1, -1, -1, 1, 1, -1};
1367std::vector<float> mu_pt {56, 45, 32, 24, 12, 8, 7, 6.2};
1368std::vector<float> mu_eta {3.1, -.2, -1.1, 1, 4.1, 1.6, 2.4, -.5};
1369~~~
1370Suppose you want to extract the transverse momenta of the muons satisfying certain
1371criteria, for example consider only negatively charged muons with a pseudorapidity
1372smaller or equal to 2 and with a transverse momentum greater than 10 GeV.
1373Such a selection would require, among the other things, the management of an explicit
1374loop, for example:
1375~~~{.cpp}
1376std::vector<float> goodMuons_pt;
1377const auto size = mu_charge.size();
1378for (size_t i=0; i < size; ++i) {
1379 if (mu_pt[i] > 10 && abs(mu_eta[i]) <= 2. && mu_charge[i] == -1) {
1380 goodMuons_pt.emplace_back(mu_pt[i]);
1381 }
1382}
1383~~~
1384These operations become straightforward with RVec - we just need to *write what
1385we mean*:
1386~~~{.cpp}
1387auto goodMuons_pt = mu_pt[ (mu_pt > 10.f && abs(mu_eta) <= 2.f && mu_charge == -1) ]
1388~~~
1389Now the clean collection of transverse momenta can be used within the rest of the data analysis, for
1390example to fill a histogram.
1391
1392\anchor operationsandfunctions
1393## Arithmetic operations, logical operations and mathematical functions
1394Arithmetic operations on RVec instances can be performed: for example, they can be added, subtracted, multiplied.
1395~~~{.cpp}
1396RVec<double> v1 {1.,2.,3.,4.};
1397RVec<float> v2 {5.f,6.f,7.f,8.f};
1398auto v3 = v1+v2;
1399auto v4 = 3 * v1;
1400~~~
1401The supported operators are
1402 - +, -, *, /
1403 - +=, -=, *=, /=
1404 - <, >, ==, !=, <=, >=, &&, ||
1405 - ~, !
1406 - &, |, ^
1407 - &=, |=, ^=
1408 - <<=, >>=
1409
1410The most common mathematical functions are supported. It is possible to invoke them passing
1411RVecs as arguments.
1412 - abs, fdim, fmod, remainder
1413 - floor, ceil, trunc, round, lround, llround
1414 - exp, exp2, expm1
1415 - log, log10, log2, log1p
1416 - pow
1417 - sqrt, cbrt
1418 - sin, cos, tan, asin, acos, atan, atan2, hypot
1419 - sinh, cosh, tanh, asinh, acosh
1420 - erf, erfc
1421 - lgamma, tgamma
1422
1423If the VDT library is available, the following functions can be invoked. Internally the calculations
1424are vectorized:
1425 - fast_expf, fast_logf, fast_sinf, fast_cosf, fast_tanf, fast_asinf, fast_acosf, fast_atanf
1426 - fast_exp, fast_log, fast_sin, fast_cos, fast_tan, fast_asin, fast_acos, fast_atan
1427
1428\anchor owningandadoptingmemory
1429## Owning and adopting memory
1430RVec has contiguous memory associated to it. It can own it or simply adopt it. In the latter case,
1431it can be constructed with the address of the memory associated to it and its length. For example:
1432~~~{.cpp}
1433std::vector<int> myStlVec {1,2,3};
1434RVec<int> myRVec(myStlVec.data(), myStlVec.size());
1435~~~
1436In this case, the memory associated to myStlVec and myRVec is the same, myRVec simply "adopted it".
1437If any method which implies a re-allocation is called, e.g. *emplace_back* or *resize*, the adopted
1438memory is released and new one is allocated. The previous content is copied in the new memory and
1439preserved.
1440
1441\anchor sorting
1442## Sorting and manipulation of indices
1443
1444### Sorting
1445RVec complies to the STL interfaces when it comes to iterations. As a result, standard algorithms
1446can be used, for example sorting:
1447~~~{.cpp}
1448RVec<double> v{6., 4., 5.};
1449std::sort(v.begin(), v.end());
1450~~~
1451
1452For convenience, helpers are provided too:
1453~~~{.cpp}
1454auto sorted_v = Sort(v);
1455auto reversed_v = Reverse(v);
1456~~~
1457
1458### Manipulation of indices
1459
1460It is also possible to manipulated the RVecs acting on their indices. For example,
1461the following syntax
1462~~~{.cpp}
1463RVecD v0 {9., 7., 8.};
1464auto v1 = Take(v0, {1, 2, 0});
1465~~~
1466will yield a new RVec<double> the content of which is the first, second and zeroth element of
1467v0, i.e. `{7., 8., 9.}`.
1468
1469The `Argsort` and `StableArgsort` helper extracts the indices which order the content of a `RVec`.
1470For example, this snippet accomplishes in a more expressive way what we just achieved:
1471~~~{.cpp}
1472auto v1_indices = Argsort(v0); // The content of v1_indices is {1, 2, 0}.
1473v1 = Take(v0, v1_indices);
1474~~~
1475
1476The `Take` utility allows to extract portions of the `RVec`. The content to be *taken*
1477can be specified with an `RVec` of indices or an integer. If the integer is negative,
1478elements will be picked starting from the end of the container:
1479~~~{.cpp}
1480RVecF vf {1.f, 2.f, 3.f, 4.f};
1481auto vf_1 = Take(vf, {1, 3}); // The content is {2.f, 4.f}
1482auto vf_2 = Take(vf, 2); // The content is {1.f, 2.f}
1483auto vf_3 = Take(vf, -3); // The content is {2.f, 3.f, 4.f}
1484~~~
1485
1486\anchor usagetdataframe
1487## Usage in combination with RDataFrame
1488RDataFrame leverages internally RVecs. Suppose to have a dataset stored in a
1489TTree which holds these columns (here we choose C arrays to represent the
1490collections, they could be as well std::vector instances):
1491~~~{.bash}
1492 nPart "nPart/I" An integer representing the number of particles
1493 px "px[nPart]/D" The C array of the particles' x component of the momentum
1494 py "py[nPart]/D" The C array of the particles' y component of the momentum
1495 E "E[nPart]/D" The C array of the particles' Energy
1496~~~
1497Suppose you'd like to plot in a histogram the transverse momenta of all particles
1498for which the energy is greater than 200 MeV.
1499The code required would just be:
1500~~~{.cpp}
1501RDataFrame d("mytree", "myfile.root");
1502auto cutPt = [](RVecD &pxs, RVecD &pys, RVecD &Es) {
1503 auto all_pts = sqrt(pxs * pxs + pys * pys);
1504 auto good_pts = all_pts[Es > 200.];
1505 return good_pts;
1506 };
1507
1508auto hpt = d.Define("pt", cutPt, {"px", "py", "E"})
1509 .Histo1D("pt");
1510hpt->Draw();
1511~~~
1512And if you'd like to express your selection as a string:
1513~~~{.cpp}
1514RDataFrame d("mytree", "myfile.root");
1515auto hpt = d.Define("pt", "sqrt(pxs * pxs + pys * pys)[E>200]")
1516 .Histo1D("pt");
1517hpt->Draw();
1518~~~
1519\anchor RVecdoxyref
1520**/
1521// clang-format on
1522
1523template <typename T>
1524class R__CLING_PTRCHECK(off) RVec : public RVecN<T, Internal::VecOps::RVecInlineStorageSize<T>::value> {
1526
1527 friend void Internal::VecOps::ResetView<>(RVec<T> &v, T *addr, std::size_t sz);
1528
1529public:
1534 using SuperClass::begin;
1535 using SuperClass::size;
1536
1537 RVec() {}
1538
1539 explicit RVec(size_t Size, const T &Value) : SuperClass(Size, Value) {}
1540
1541 explicit RVec(size_t Size) : SuperClass(Size) {}
1542
1543 template <typename ItTy,
1544 typename = typename std::enable_if<std::is_convertible<
1545 typename std::iterator_traits<ItTy>::iterator_category, std::input_iterator_tag>::value>::type>
1546 RVec(ItTy S, ItTy E) : SuperClass(S, E)
1547 {
1548 }
1549
1550 RVec(std::initializer_list<T> IL) : SuperClass(IL) {}
1551
1553
1555 {
1556 SuperClass::operator=(RHS);
1557 return *this;
1558 }
1559
1561
1563 {
1564 SuperClass::operator=(std::move(RHS));
1565 return *this;
1566 }
1567
1569
1570 template <unsigned N>
1572
1573 template <unsigned N>
1575
1576 RVec(const std::vector<T> &RHS) : SuperClass(RHS) {}
1577
1578 RVec(T* p, size_t n) : SuperClass(p, n) {}
1579
1580 // conversion
1582 operator RVec<U>() const
1583 {
1584 return RVec<U>(this->begin(), this->end());
1585 }
1586
1587 using SuperClass::operator[];
1588
1591 {
1592 return RVec(SuperClass::operator[](conds));
1593 }
1594
1595 using SuperClass::at;
1596
1597 friend bool ROOT::Detail::VecOps::IsSmall<T>(const RVec<T> &v);
1598
1599 friend bool ROOT::Detail::VecOps::IsAdopting<T>(const RVec<T> &v);
1600};
1601
1602template <typename T, unsigned N>
1603inline size_t CapacityInBytes(const RVecN<T, N> &X)
1604{
1605 return X.capacity_in_bytes();
1606}
1607
1608///@name RVec Unary Arithmetic Operators
1609///@{
1610
1611#define RVEC_UNARY_OPERATOR(OP) \
1612template <typename T> \
1613RVec<T> operator OP(const RVec<T> &v) \
1614{ \
1615 RVec<T> ret(v); \
1616 for (auto &x : ret) \
1617 x = OP x; \
1618return ret; \
1619} \
1620
1625#undef RVEC_UNARY_OPERATOR
1626
1627///@}
1628///@name RVec Binary Arithmetic Operators
1629///@{
1630
1631#define ERROR_MESSAGE(OP) \
1632 "Cannot call operator " #OP " on vectors of different sizes."
1633
1634#define RVEC_BINARY_OPERATOR(OP) \
1635template <typename T0, typename T1> \
1636auto operator OP(const RVec<T0> &v, const T1 &y) \
1637 -> RVec<decltype(v[0] OP y)> \
1638{ \
1639 RVec<decltype(v[0] OP y)> ret(v.size()); \
1640 auto op = [&y](const T0 &x) { return x OP y; }; \
1641 std::transform(v.begin(), v.end(), ret.begin(), op); \
1642 return ret; \
1643} \
1644 \
1645template <typename T0, typename T1> \
1646auto operator OP(const T0 &x, const RVec<T1> &v) \
1647 -> RVec<decltype(x OP v[0])> \
1648{ \
1649 RVec<decltype(x OP v[0])> ret(v.size()); \
1650 auto op = [&x](const T1 &y) { return x OP y; }; \
1651 std::transform(v.begin(), v.end(), ret.begin(), op); \
1652 return ret; \
1653} \
1654 \
1655template <typename T0, typename T1> \
1656auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
1657 -> RVec<decltype(v0[0] OP v1[0])> \
1658{ \
1659 if (v0.size() != v1.size()) \
1660 throw std::runtime_error(ERROR_MESSAGE(OP)); \
1661 \
1662 RVec<decltype(v0[0] OP v1[0])> ret(v0.size()); \
1663 auto op = [](const T0 &x, const T1 &y) { return x OP y; }; \
1664 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
1665 return ret; \
1666} \
1667
1676#undef RVEC_BINARY_OPERATOR
1677
1678///@}
1679///@name RVec Assignment Arithmetic Operators
1680///@{
1681
1682#define RVEC_ASSIGNMENT_OPERATOR(OP) \
1683template <typename T0, typename T1> \
1684RVec<T0>& operator OP(RVec<T0> &v, const T1 &y) \
1685{ \
1686 auto op = [&y](T0 &x) { return x OP y; }; \
1687 std::transform(v.begin(), v.end(), v.begin(), op); \
1688 return v; \
1689} \
1690 \
1691template <typename T0, typename T1> \
1692RVec<T0>& operator OP(RVec<T0> &v0, const RVec<T1> &v1) \
1693{ \
1694 if (v0.size() != v1.size()) \
1695 throw std::runtime_error(ERROR_MESSAGE(OP)); \
1696 \
1697 auto op = [](T0 &x, const T1 &y) { return x OP y; }; \
1698 std::transform(v0.begin(), v0.end(), v1.begin(), v0.begin(), op); \
1699 return v0; \
1700} \
1701
1712#undef RVEC_ASSIGNMENT_OPERATOR
1713
1714///@}
1715///@name RVec Comparison and Logical Operators
1716///@{
1717
1718#define RVEC_LOGICAL_OPERATOR(OP) \
1719template <typename T0, typename T1> \
1720auto operator OP(const RVec<T0> &v, const T1 &y) \
1721 -> RVec<int> /* avoid std::vector<bool> */ \
1722{ \
1723 RVec<int> ret(v.size()); \
1724 auto op = [y](const T0 &x) -> int { return x OP y; }; \
1725 std::transform(v.begin(), v.end(), ret.begin(), op); \
1726 return ret; \
1727} \
1728 \
1729template <typename T0, typename T1> \
1730auto operator OP(const T0 &x, const RVec<T1> &v) \
1731 -> RVec<int> /* avoid std::vector<bool> */ \
1732{ \
1733 RVec<int> ret(v.size()); \
1734 auto op = [x](const T1 &y) -> int { return x OP y; }; \
1735 std::transform(v.begin(), v.end(), ret.begin(), op); \
1736 return ret; \
1737} \
1738 \
1739template <typename T0, typename T1> \
1740auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
1741 -> RVec<int> /* avoid std::vector<bool> */ \
1742{ \
1743 if (v0.size() != v1.size()) \
1744 throw std::runtime_error(ERROR_MESSAGE(OP)); \
1745 \
1746 RVec<int> ret(v0.size()); \
1747 auto op = [](const T0 &x, const T1 &y) -> int { return x OP y; }; \
1748 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
1749 return ret; \
1750} \
1751
1760#undef RVEC_LOGICAL_OPERATOR
1761
1762///@}
1763///@name RVec Standard Mathematical Functions
1764///@{
1765
1766/// \cond
1767template <typename T> struct PromoteTypeImpl;
1768
1769template <> struct PromoteTypeImpl<float> { using Type = float; };
1770template <> struct PromoteTypeImpl<double> { using Type = double; };
1771template <> struct PromoteTypeImpl<long double> { using Type = long double; };
1772
1773template <typename T> struct PromoteTypeImpl { using Type = double; };
1774
1775template <typename T>
1776using PromoteType = typename PromoteTypeImpl<T>::Type;
1777
1778template <typename U, typename V>
1779using PromoteTypes = decltype(PromoteType<U>() + PromoteType<V>());
1780
1781/// \endcond
1782
1783#define RVEC_UNARY_FUNCTION(NAME, FUNC) \
1784 template <typename T> \
1785 RVec<PromoteType<T>> NAME(const RVec<T> &v) \
1786 { \
1787 RVec<PromoteType<T>> ret(v.size()); \
1788 auto f = [](const T &x) { return FUNC(x); }; \
1789 std::transform(v.begin(), v.end(), ret.begin(), f); \
1790 return ret; \
1791 }
1792
1793#define RVEC_BINARY_FUNCTION(NAME, FUNC) \
1794 template <typename T0, typename T1> \
1795 RVec<PromoteTypes<T0, T1>> NAME(const T0 &x, const RVec<T1> &v) \
1796 { \
1797 RVec<PromoteTypes<T0, T1>> ret(v.size()); \
1798 auto f = [&x](const T1 &y) { return FUNC(x, y); }; \
1799 std::transform(v.begin(), v.end(), ret.begin(), f); \
1800 return ret; \
1801 } \
1802 \
1803 template <typename T0, typename T1> \
1804 RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v, const T1 &y) \
1805 { \
1806 RVec<PromoteTypes<T0, T1>> ret(v.size()); \
1807 auto f = [&y](const T0 &x) { return FUNC(x, y); }; \
1808 std::transform(v.begin(), v.end(), ret.begin(), f); \
1809 return ret; \
1810 } \
1811 \
1812 template <typename T0, typename T1> \
1813 RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v0, const RVec<T1> &v1) \
1814 { \
1815 if (v0.size() != v1.size()) \
1816 throw std::runtime_error(ERROR_MESSAGE(NAME)); \
1817 \
1818 RVec<PromoteTypes<T0, T1>> ret(v0.size()); \
1819 auto f = [](const T0 &x, const T1 &y) { return FUNC(x, y); }; \
1820 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), f); \
1821 return ret; \
1822 } \
1823
1824#define RVEC_STD_UNARY_FUNCTION(F) RVEC_UNARY_FUNCTION(F, std::F)
1825#define RVEC_STD_BINARY_FUNCTION(F) RVEC_BINARY_FUNCTION(F, std::F)
1826
1831
1835
1840
1845
1853
1860
1867
1872#undef RVEC_STD_UNARY_FUNCTION
1873
1874///@}
1875///@name RVec Fast Mathematical Functions with Vdt
1876///@{
1877
1878#ifdef R__HAS_VDT
1879#define RVEC_VDT_UNARY_FUNCTION(F) RVEC_UNARY_FUNCTION(F, vdt::F)
1880
1889
1898#undef RVEC_VDT_UNARY_FUNCTION
1899
1900#endif // R__HAS_VDT
1901
1902#undef RVEC_UNARY_FUNCTION
1903
1904///@}
1905
1906/// Inner product
1907///
1908/// Example code, at the ROOT prompt:
1909/// ~~~{.cpp}
1910/// using namespace ROOT::VecOps;
1911/// RVec<float> v1 {1., 2., 3.};
1912/// RVec<float> v2 {4., 5., 6.};
1913/// auto v1_dot_v2 = Dot(v1, v2);
1914/// v1_dot_v2
1915/// // (float) 32.0000f
1916/// ~~~
1917template <typename T, typename V>
1918auto Dot(const RVec<T> &v0, const RVec<V> &v1) -> decltype(v0[0] * v1[0])
1919{
1920 if (v0.size() != v1.size())
1921 throw std::runtime_error("Cannot compute inner product of vectors of different sizes");
1922 return std::inner_product(v0.begin(), v0.end(), v1.begin(), decltype(v0[0] * v1[0])(0));
1923}
1924
1925/// Sum elements of an RVec
1926///
1927/// Example code, at the ROOT prompt:
1928/// ~~~{.cpp}
1929/// using namespace ROOT::VecOps;
1930/// RVecF v {1.f, 2.f, 3.f};
1931/// auto v_sum = Sum(v);
1932/// v_sum
1933/// // (float) 6.f
1934/// auto v_sum_d = Sum(v, 0.);
1935/// v_sum_d
1936/// // (double) 6.0000000
1937/// ~~~
1938/// ~~~{.cpp}
1939/// using namespace ROOT::VecOps;
1940/// const ROOT::Math::PtEtaPhiMVector lv0 {15.5f, .3f, .1f, 105.65f},
1941/// lv1 {34.32f, 2.2f, 3.02f, 105.65f},
1942/// lv2 {12.95f, 1.32f, 2.2f, 105.65f};
1943/// RVec<ROOT::Math::PtEtaPhiMVector> v {lv0, lv1, lv2};
1944/// auto v_sum_lv = Sum(v, ROOT::Math::PtEtaPhiMVector());
1945/// v_sum_lv
1946/// // (ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double> > &) (30.8489,2.46534,2.58947,361.084)
1947/// ~~~
1948template <typename T>
1949T Sum(const RVec<T> &v, const T zero = T(0))
1950{
1951 return std::accumulate(v.begin(), v.end(), zero);
1952}
1953
1954inline std::size_t Sum(const RVec<bool> &v, std::size_t zero = 0ul)
1955{
1956 return std::accumulate(v.begin(), v.end(), zero);
1957}
1958
1959/// Return the product of the elements of the RVec.
1960template <typename T>
1961T Product(const RVec<T> &v, const T init = T(1)) // initialize with identity
1962{
1963 return std::accumulate(v.begin(), v.end(), init, std::multiplies<T>());
1964}
1965
1966/// Get the mean of the elements of an RVec
1967///
1968/// The return type is a double precision floating point number.
1969///
1970/// Example code, at the ROOT prompt:
1971/// ~~~{.cpp}
1972/// using namespace ROOT::VecOps;
1973/// RVecF v {1.f, 2.f, 4.f};
1974/// auto v_mean = Mean(v);
1975/// v_mean
1976/// // (double) 2.3333333
1977/// ~~~
1978template <typename T>
1979double Mean(const RVec<T> &v)
1980{
1981 if (v.empty()) return 0.;
1982 return double(Sum(v)) / v.size();
1983}
1984
1985/// Get the mean of the elements of an RVec with custom initial value
1986///
1987/// The return type will be deduced from the `zero` parameter
1988///
1989/// Example code, at the ROOT prompt:
1990/// ~~~{.cpp}
1991/// using namespace ROOT::VecOps;
1992/// RVecF v {1.f, 2.f, 4.f};
1993/// auto v_mean_f = Mean(v, 0.f);
1994/// v_mean_f
1995/// // (float) 2.33333f
1996/// auto v_mean_d = Mean(v, 0.);
1997/// v_mean_d
1998/// // (double) 2.3333333
1999/// ~~~
2000/// ~~~{.cpp}
2001/// using namespace ROOT::VecOps;
2002/// const ROOT::Math::PtEtaPhiMVector lv0 {15.5f, .3f, .1f, 105.65f},
2003/// lv1 {34.32f, 2.2f, 3.02f, 105.65f},
2004/// lv2 {12.95f, 1.32f, 2.2f, 105.65f};
2005/// RVec<ROOT::Math::PtEtaPhiMVector> v {lv0, lv1, lv2};
2006/// auto v_mean_lv = Mean(v, ROOT::Math::PtEtaPhiMVector());
2007/// v_mean_lv
2008/// // (ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double> > &) (10.283,2.46534,2.58947,120.361)
2009/// ~~~
2010template <typename T, typename R = T>
2011R Mean(const RVec<T> &v, const R zero)
2012{
2013 if (v.empty()) return zero;
2014 return Sum(v, zero) / v.size();
2015}
2016
2017/// Get the greatest element of an RVec
2018///
2019/// Example code, at the ROOT prompt:
2020/// ~~~{.cpp}
2021/// using namespace ROOT::VecOps;
2022/// RVecF v {1.f, 2.f, 4.f};
2023/// auto v_max = Max(v);
2024/// v_max
2025/// (float) 4.00000f
2026/// ~~~
2027template <typename T>
2028T Max(const RVec<T> &v)
2029{
2030 return *std::max_element(v.begin(), v.end());
2031}
2032
2033/// Get the smallest element of an RVec
2034///
2035/// Example code, at the ROOT prompt:
2036/// ~~~{.cpp}
2037/// using namespace ROOT::VecOps;
2038/// RVecF v {1.f, 2.f, 4.f};
2039/// auto v_min = Min(v);
2040/// v_min
2041/// (float) 1.00000f
2042/// ~~~
2043template <typename T>
2044T Min(const RVec<T> &v)
2045{
2046 return *std::min_element(v.begin(), v.end());
2047}
2048
2049/// Get the index of the greatest element of an RVec
2050/// In case of multiple occurrences of the maximum values,
2051/// the index corresponding to the first occurrence is returned.
2052///
2053/// Example code, at the ROOT prompt:
2054/// ~~~{.cpp}
2055/// using namespace ROOT::VecOps;
2056/// RVecF v {1.f, 2.f, 4.f};
2057/// auto v_argmax = ArgMax(v);
2058/// v_argmax
2059/// // (unsigned long) 2
2060/// ~~~
2061template <typename T>
2062std::size_t ArgMax(const RVec<T> &v)
2063{
2064 return std::distance(v.begin(), std::max_element(v.begin(), v.end()));
2065}
2066
2067/// Get the index of the smallest element of an RVec
2068/// In case of multiple occurrences of the minimum values,
2069/// the index corresponding to the first occurrence is returned.
2070///
2071/// Example code, at the ROOT prompt:
2072/// ~~~{.cpp}
2073/// using namespace ROOT::VecOps;
2074/// RVecF v {1.f, 2.f, 4.f};
2075/// auto v_argmin = ArgMin(v);
2076/// v_argmin
2077/// // (unsigned long) 0
2078/// ~~~
2079template <typename T>
2080std::size_t ArgMin(const RVec<T> &v)
2081{
2082 return std::distance(v.begin(), std::min_element(v.begin(), v.end()));
2083}
2084
2085/// Get the variance of the elements of an RVec
2086///
2087/// The return type is a double precision floating point number.
2088/// Example code, at the ROOT prompt:
2089/// ~~~{.cpp}
2090/// using namespace ROOT::VecOps;
2091/// RVecF v {1.f, 2.f, 4.f};
2092/// auto v_var = Var(v);
2093/// v_var
2094/// // (double) 2.3333333
2095/// ~~~
2096template <typename T>
2097double Var(const RVec<T> &v)
2098{
2099 const std::size_t size = v.size();
2100 if (size < std::size_t(2)) return 0.;
2101 T sum_squares(0), squared_sum(0);
2102 auto pred = [&sum_squares, &squared_sum](const T& x) {sum_squares+=x*x; squared_sum+=x;};
2103 std::for_each(v.begin(), v.end(), pred);
2105 const auto dsize = (double) size;
2106 return 1. / (dsize - 1.) * (sum_squares - squared_sum / dsize );
2107}
2108
2109/// Get the standard deviation of the elements of an RVec
2110///
2111/// The return type is a double precision floating point number.
2112/// Example code, at the ROOT prompt:
2113/// ~~~{.cpp}
2114/// using namespace ROOT::VecOps;
2115/// RVecF v {1.f, 2.f, 4.f};
2116/// auto v_sd = StdDev(v);
2117/// v_sd
2118/// // (double) 1.5275252
2119/// ~~~
2120template <typename T>
2121double StdDev(const RVec<T> &v)
2122{
2123 return std::sqrt(Var(v));
2124}
2125
2126/// Create new collection applying a callable to the elements of the input collection
2127///
2128/// Example code, at the ROOT prompt:
2129/// ~~~{.cpp}
2130/// using namespace ROOT::VecOps;
2131/// RVecF v {1.f, 2.f, 4.f};
2132/// auto v_square = Map(v, [](float f){return f* 2.f;});
2133/// v_square
2134/// // (ROOT::VecOps::RVec<float> &) { 2.00000f, 4.00000f, 8.00000f }
2135///
2136/// RVecF x({1.f, 2.f, 3.f});
2137/// RVecF y({4.f, 5.f, 6.f});
2138/// RVecF z({7.f, 8.f, 9.f});
2139/// auto mod = [](float x, float y, float z) { return sqrt(x * x + y * y + z * z); };
2140/// auto v_mod = Map(x, y, z, mod);
2141/// v_mod
2142/// // (ROOT::VecOps::RVec<float> &) { 8.12404f, 9.64365f, 11.2250f }
2143/// ~~~
2144template <typename... Args>
2145auto Map(Args &&... args)
2146{
2147 /*
2148 Here the strategy in order to generalise the previous implementation of Map, i.e.
2149 `RVec Map(RVec, F)`, here we need to move the last parameter of the pack in first
2150 position in order to be able to invoke the Map function with automatic type deduction.
2151 This is achieved in two steps:
2152 1. Forward as tuple the pack to MapFromTuple
2153 2. Invoke the MapImpl helper which has the signature `template<...T, F> RVec MapImpl(F &&f, RVec<T>...)`
2154 */
2155
2156 // check the first N - 1 arguments are RVecs
2157 constexpr auto nArgs = sizeof...(Args);
2159 static_assert(ROOT::Internal::VecOps::All(isRVec, nArgs - 1),
2160 "Map: the first N-1 arguments must be RVecs or references to RVecs");
2161
2162 return ROOT::Internal::VecOps::MapFromTuple(std::forward_as_tuple(args...),
2163 std::make_index_sequence<sizeof...(args) - 1>());
2164}
2165
2166/// Create a new collection with the elements passing the filter expressed by the predicate
2167///
2168/// Example code, at the ROOT prompt:
2169/// ~~~{.cpp}
2170/// using namespace ROOT::VecOps;
2171/// RVecI v {1, 2, 4};
2172/// auto v_even = Filter(v, [](int i){return 0 == i%2;});
2173/// v_even
2174/// // (ROOT::VecOps::RVec<int> &) { 2, 4 }
2175/// ~~~
2176template <typename T, typename F>
2178{
2179 const auto thisSize = v.size();
2180 RVec<T> w;
2181 w.reserve(thisSize);
2182 for (auto &&val : v) {
2183 if (f(val))
2184 w.emplace_back(val);
2185 }
2186 return w;
2187}
2188
2189/// Return true if any of the elements equates to true, return false otherwise.
2190///
2191/// Example code, at the ROOT prompt:
2192/// ~~~{.cpp}
2193/// using namespace ROOT::VecOps;
2194/// RVecI v {0, 1, 0};
2195/// auto anyTrue = Any(v);
2196/// anyTrue
2197/// // (bool) true
2198/// ~~~
2199template <typename T>
2200auto Any(const RVec<T> &v) -> decltype(v[0] == true)
2201{
2202 for (auto &&e : v)
2203 if (static_cast<bool>(e) == true)
2204 return true;
2205 return false;
2206}
2207
2208/// Return true if all of the elements equate to true, return false otherwise.
2209///
2210/// Example code, at the ROOT prompt:
2211/// ~~~{.cpp}
2212/// using namespace ROOT::VecOps;
2213/// RVecI v {0, 1, 0};
2214/// auto allTrue = All(v);
2215/// allTrue
2216/// // (bool) false
2217/// ~~~
2218template <typename T>
2219auto All(const RVec<T> &v) -> decltype(v[0] == false)
2220{
2221 for (auto &&e : v)
2222 if (static_cast<bool>(e) == false)
2223 return false;
2224 return true;
2225}
2226
2227template <typename T>
2229{
2230 lhs.swap(rhs);
2231}
2232
2233/// Return an RVec of indices that sort the input RVec
2234///
2235/// Example code, at the ROOT prompt:
2236/// ~~~{.cpp}
2237/// using namespace ROOT::VecOps;
2238/// RVecD v {2., 3., 1.};
2239/// auto sortIndices = Argsort(v)
2240/// // (ROOT::VecOps::RVec<unsigned long> &) { 2, 0, 1 }
2241/// auto values = Take(v, sortIndices)
2242/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 2.0000000, 3.0000000 }
2243/// ~~~
2244template <typename T>
2246{
2247 using size_type = typename RVec<T>::size_type;
2248 RVec<size_type> i(v.size());
2249 std::iota(i.begin(), i.end(), 0);
2250 std::sort(i.begin(), i.end(), [&v](size_type i1, size_type i2) { return v[i1] < v[i2]; });
2251 return i;
2252}
2253
2254/// Return an RVec of indices that sort the input RVec based on a comparison function.
2255///
2256/// Example code, at the ROOT prompt:
2257/// ~~~{.cpp}
2258/// using namespace ROOT::VecOps;
2259/// RVecD v {2., 3., 1.};
2260/// auto sortIndices = Argsort(v, [](double x, double y) {return x > y;})
2261/// // (ROOT::VecOps::RVec<unsigned long> &) { 1, 0, 2 }
2262/// auto values = Take(v, sortIndices)
2263/// // (ROOT::VecOps::RVec<double> &) { 3.0000000, 2.0000000, 1.0000000 }
2264/// ~~~
2265template <typename T, typename Compare>
2267{
2268 using size_type = typename RVec<T>::size_type;
2269 RVec<size_type> i(v.size());
2270 std::iota(i.begin(), i.end(), 0);
2271 std::sort(i.begin(), i.end(),
2272 [&v, &c](size_type i1, size_type i2) { return c(v[i1], v[i2]); });
2273 return i;
2274}
2275
2276/// Return an RVec of indices that sort the input RVec
2277/// while keeping the order of equal elements.
2278/// This is the stable variant of `Argsort`.
2279///
2280/// Example code, at the ROOT prompt:
2281/// ~~~{.cpp}
2282/// using namespace ROOT::VecOps;
2283/// RVecD v {2., 3., 2., 1.};
2284/// auto sortIndices = StableArgsort(v)
2285/// // (ROOT::VecOps::RVec<unsigned long> &) { 3, 0, 2, 1 }
2286/// auto values = Take(v, sortIndices)
2287/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 2.0000000, 2.0000000, 3.0000000 }
2288/// ~~~
2289template <typename T>
2291{
2292 using size_type = typename RVec<T>::size_type;
2293 RVec<size_type> i(v.size());
2294 std::iota(i.begin(), i.end(), 0);
2295 std::stable_sort(i.begin(), i.end(), [&v](size_type i1, size_type i2) { return v[i1] < v[i2]; });
2296 return i;
2297}
2298
2299/// Return an RVec of indices that sort the input RVec based on a comparison function
2300/// while keeping the order of equal elements.
2301/// This is the stable variant of `Argsort`.
2302///
2303/// Example code, at the ROOT prompt:
2304/// ~~~{.cpp}
2305/// using namespace ROOT::VecOps;
2306/// RVecD v {2., 3., 2., 1.};
2307/// auto sortIndices = StableArgsort(v, [](double x, double y) {return x > y;})
2308/// // (ROOT::VecOps::RVec<unsigned long> &) { 1, 0, 2, 3 }
2309/// auto values = Take(v, sortIndices)
2310/// // (ROOT::VecOps::RVec<double> &) { 3.0000000, 2.0000000, 2.0000000, 1.0000000 }
2311/// ~~~
2312template <typename T, typename Compare>
2314{
2315 using size_type = typename RVec<T>::size_type;
2316 RVec<size_type> i(v.size());
2317 std::iota(i.begin(), i.end(), 0);
2318 std::stable_sort(i.begin(), i.end(), [&v, &c](size_type i1, size_type i2) { return c(v[i1], v[i2]); });
2319 return i;
2320}
2321
2322/// Return elements of a vector at given indices
2323///
2324/// Example code, at the ROOT prompt:
2325/// ~~~{.cpp}
2326/// using namespace ROOT::VecOps;
2327/// RVecD v {2., 3., 1.};
2328/// auto vTaken = Take(v, {0,2});
2329/// vTaken
2330/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 1.0000000 }
2331/// ~~~
2332
2333template <typename T>
2334RVec<T> Take(const RVec<T> &v, const RVec<typename RVec<T>::size_type> &i)
2335{
2336 using size_type = typename RVec<T>::size_type;
2337 const size_type isize = i.size();
2338 RVec<T> r(isize);
2339 for (size_type k = 0; k < isize; k++)
2340 r[k] = v[i[k]];
2341 return r;
2342}
2343
2344/// Take version that defaults to (user-specified) output value if some index is out of range
2345template <typename T>
2346RVec<T> Take(const RVec<T> &v, const RVec<typename RVec<T>::size_type> &i, const T default_val)
2347{
2348 using size_type = typename RVec<T>::size_type;
2349 const size_type isize = i.size();
2350 RVec<T> r(isize);
2351 for (size_type k = 0; k < isize; k++)
2352 {
2353 if (i[k] < v.size() && i[k]>=0){
2354 r[k] = v[i[k]];
2355 }
2356 else {
2357 r[k] = default_val;
2358 }
2359 }
2360 return r;
2361}
2362
2363/// Return first `n` elements of an RVec if `n > 0` and last `n` elements if `n < 0`.
2364///
2365/// Example code, at the ROOT prompt:
2366/// ~~~{.cpp}
2367/// using namespace ROOT::VecOps;
2368/// RVecD v {2., 3., 1.};
2369/// auto firstTwo = Take(v, 2);
2370/// firstTwo
2371/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 3.0000000 }
2372/// auto lastOne = Take(v, -1);
2373/// lastOne
2374/// // (ROOT::VecOps::RVec<double>) { 1.0000000 }
2375/// ~~~
2376template <typename T>
2377RVec<T> Take(const RVec<T> &v, const int n)
2378{
2379 using size_type = typename RVec<T>::size_type;
2380 const size_type size = v.size();
2381 const size_type absn = std::abs(n);
2382 if (absn > size) {
2383 const auto msg = std::to_string(absn) + " elements requested from Take but input contains only " +
2384 std::to_string(size) + " elements.";
2385 throw std::runtime_error(msg);
2386 }
2387 RVec<T> r(absn);
2388 if (n < 0) {
2389 for (size_type k = 0; k < absn; k++)
2390 r[k] = v[size - absn + k];
2391 } else {
2392 for (size_type k = 0; k < absn; k++)
2393 r[k] = v[k];
2394 }
2395 return r;
2396}
2397
2398/// Return first `n` elements of an RVec if `n > 0` and last `n` elements if `n < 0`.
2399///
2400/// This Take version defaults to a user-specified value
2401/// `default_val` if the absolute value of `n` is
2402/// greater than the size of the RVec `v`
2403///
2404/// Example code, at the ROOT prompt:
2405/// ~~~{.cpp}
2406/// using ROOT::VecOps::RVec;
2407/// RVec<int> x{1,2,3,4};
2408/// Take(x,-5,1)
2409/// // (ROOT::VecOps::RVec<int>) { 1, 1, 2, 3, 4 }
2410/// Take(x,5,20)
2411/// // (ROOT::VecOps::RVec<int>) { 1, 2, 3, 4, 20 }
2412/// Take(x,-1,1)
2413/// // (ROOT::VecOps::RVec<int>) { 4 }
2414/// Take(x,4,1)
2415/// // (ROOT::VecOps::RVec<int>) { 1, 2, 3, 4 }
2416/// ~~~
2417template <typename T>
2418RVec<T> Take(const RVec<T> &v, const int n, const T default_val)
2419{
2420 using size_type = typename RVec<T>::size_type;
2421 const size_type size = v.size();
2422 const size_type absn = std::abs(n);
2423 // Base case, can be handled by another overload of Take
2424 if (absn <= size) {
2425 return Take(v, n);
2426 }
2427 RVec<T> temp = v;
2428 // Case when n is positive and n > v.size()
2429 if (n > 0) {
2430 temp.resize(n, default_val);
2431 return temp;
2432 }
2433 // Case when n is negative and abs(n) > v.size()
2434 const auto num_to_fill = absn - size;
2436 return Concatenate(fill_front, temp);
2437}
2438
2439/// Return a copy of the container without the elements at the specified indices.
2440///
2441/// Duplicated and out-of-range indices in idxs are ignored.
2442template <typename T>
2444{
2445 // clean up input indices
2446 std::sort(idxs.begin(), idxs.end());
2447 idxs.erase(std::unique(idxs.begin(), idxs.end()), idxs.end());
2448
2449 RVec<T> r;
2450 if (v.size() > idxs.size())
2451 r.reserve(v.size() - idxs.size());
2452
2453 auto discardIt = idxs.begin();
2454 using sz_t = typename RVec<T>::size_type;
2455 for (sz_t i = 0u; i < v.size(); ++i) {
2456 if (discardIt != idxs.end() && i == *discardIt)
2457 ++discardIt;
2458 else
2459 r.emplace_back(v[i]);
2460 }
2461
2462 return r;
2463}
2464
2465/// Return copy of reversed vector
2466///
2467/// Example code, at the ROOT prompt:
2468/// ~~~{.cpp}
2469/// using namespace ROOT::VecOps;
2470/// RVecD v {2., 3., 1.};
2471/// auto v_reverse = Reverse(v);
2472/// v_reverse
2473/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 3.0000000, 2.0000000 }
2474/// ~~~
2475template <typename T>
2477{
2478 RVec<T> r(v);
2479 std::reverse(r.begin(), r.end());
2480 return r;
2481}
2482
2483/// Return copy of RVec with elements sorted in ascending order
2484///
2485/// This helper is different from Argsort since it does not return an RVec of indices,
2486/// but an RVec of values.
2487///
2488/// Example code, at the ROOT prompt:
2489/// ~~~{.cpp}
2490/// using namespace ROOT::VecOps;
2491/// RVecD v {2., 3., 1.};
2492/// auto v_sorted = Sort(v);
2493/// v_sorted
2494/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 2.0000000, 3.0000000 }
2495/// ~~~
2496template <typename T>
2497RVec<T> Sort(const RVec<T> &v)
2498{
2499 RVec<T> r(v);
2500 std::sort(r.begin(), r.end());
2501 return r;
2502}
2503
2504/// Return copy of RVec with elements sorted based on a comparison operator
2505///
2506/// The comparison operator has to fulfill the same requirements of the
2507/// predicate of by std::sort.
2508///
2509///
2510/// This helper is different from Argsort since it does not return an RVec of indices,
2511/// but an RVec of values.
2512///
2513/// Example code, at the ROOT prompt:
2514/// ~~~{.cpp}
2515/// using namespace ROOT::VecOps;
2516/// RVecD v {2., 3., 1.};
2517/// auto v_sorted = Sort(v, [](double x, double y) {return 1/x < 1/y;});
2518/// v_sorted
2519/// // (ROOT::VecOps::RVec<double> &) { 3.0000000, 2.0000000, 1.0000000 }
2520/// ~~~
2521template <typename T, typename Compare>
2522RVec<T> Sort(const RVec<T> &v, Compare &&c)
2523{
2524 RVec<T> r(v);
2525 std::sort(r.begin(), r.end(), std::forward<Compare>(c));
2526 return r;
2527}
2528
2529/// Return copy of RVec with elements sorted in ascending order
2530/// while keeping the order of equal elements.
2531///
2532/// This is the stable variant of `Sort`.
2533///
2534/// This helper is different from StableArgsort since it does not return an RVec of indices,
2535/// but an RVec of values.
2536///
2537/// Example code, at the ROOT prompt:
2538/// ~~~{.cpp}
2539/// using namespace ROOT::VecOps;
2540/// RVecD v {2., 3., 2, 1.};
2541/// auto v_sorted = StableSort(v);
2542/// v_sorted
2543/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 2.0000000, 2.0000000, 3.0000000 }
2544/// ~~~
2545template <typename T>
2547{
2548 RVec<T> r(v);
2549 std::stable_sort(r.begin(), r.end());
2550 return r;
2551}
2552
2553// clang-format off
2554/// Return copy of RVec with elements sorted based on a comparison operator
2555/// while keeping the order of equal elements.
2556///
2557/// The comparison operator has to fulfill the same requirements of the
2558/// predicate of std::stable_sort.
2559///
2560/// This helper is different from StableArgsort since it does not return an RVec of indices,
2561/// but an RVec of values.
2562///
2563/// This is the stable variant of `Sort`.
2564///
2565/// Example code, at the ROOT prompt:
2566/// ~~~{.cpp}
2567/// using namespace ROOT::VecOps;
2568/// RVecD v {2., 3., 2., 1.};
2569/// auto v_sorted = StableSort(v, [](double x, double y) {return 1/x < 1/y;});
2570/// v_sorted
2571/// // (ROOT::VecOps::RVec<double> &) { 3.0000000, 2.0000000, 2.0000000, 1.0000000 }
2572/// ~~~
2573/// ~~~{.cpp}
2574/// using namespace ROOT::VecOps;
2575/// RVec<RVecD> v {{2., 4.}, {3., 1.}, {2, 1.}, {1., 4.}};
2576/// auto v_sorted = StableSort(StableSort(v, [](const RVecD &x, const RVecD &y) {return x[1] < y[1];}), [](const RVecD &x, const RVecD &y) {return x[0] < y[0];});
2577/// v_sorted
2578/// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<double> > &) { { 1.0000000, 4.0000000 }, { 2.0000000, 1.0000000 }, { 2.0000000, 4.0000000 }, { 3.0000000, 1.0000000 } }
2579/// ~~~
2580// clang-format off
2581template <typename T, typename Compare>
2583{
2584 RVec<T> r(v);
2585 std::stable_sort(r.begin(), r.end(), std::forward<Compare>(c));
2586 return r;
2587}
2588
2589/// Return the indices that represent all combinations of the elements of two
2590/// RVecs.
2591///
2592/// The type of the return value is an RVec of two RVecs containing indices.
2593///
2594/// Example code, at the ROOT prompt:
2595/// ~~~{.cpp}
2596/// using namespace ROOT::VecOps;
2597/// auto comb_idx = Combinations(3, 2);
2598/// comb_idx
2599/// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0, 0, 1, 1, 2, 2 }, { 0, 1, 0, 1, 0, 1 } }
2600/// ~~~
2601inline RVec<RVec<std::size_t>> Combinations(const std::size_t size1, const std::size_t size2)
2602{
2603 using size_type = std::size_t;
2605 r[0].resize(size1*size2);
2606 r[1].resize(size1*size2);
2607 size_type c = 0;
2608 for(size_type i=0; i<size1; i++) {
2609 for(size_type j=0; j<size2; j++) {
2610 r[0][c] = i;
2611 r[1][c] = j;
2612 c++;
2613 }
2614 }
2615 return r;
2616}
2617
2618/// Return the indices that represent all combinations of the elements of two
2619/// RVecs.
2620///
2621/// The type of the return value is an RVec of two RVecs containing indices.
2622///
2623/// Example code, at the ROOT prompt:
2624/// ~~~{.cpp}
2625/// using namespace ROOT::VecOps;
2626/// RVecD v1 {1., 2., 3.};
2627/// RVecD v2 {-4., -5.};
2628/// auto comb_idx = Combinations(v1, v2);
2629/// comb_idx
2630/// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0, 0, 1, 1, 2, 2 }, { 0, 1, 0, 1, 0, 1 } }
2631/// ~~~
2632template <typename T1, typename T2>
2634{
2635 return Combinations(v1.size(), v2.size());
2636}
2637
2638/// Return the indices that represent all unique combinations of the
2639/// elements of a given RVec.
2640///
2641/// ~~~{.cpp}
2642/// using namespace ROOT::VecOps;
2643/// RVecD v {1., 2., 3., 4.};
2644/// auto v_1 = Combinations(v, 1);
2645/// v_1
2646/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0, 1, 2, 3 } }
2647/// auto v_2 = Combinations(v, 2);
2648/// v_2
2649/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0, 0, 0, 1, 1, 2 }, { 1, 2, 3, 2, 3, 3 } }
2650/// auto v_3 = Combinations(v, 3);
2651/// v_3
2652/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0, 0, 0, 1 }, { 1, 1, 2, 2 }, { 2, 3, 3, 3 } }
2653/// auto v_4 = Combinations(v, 4);
2654/// v_4
2655/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<unsigned long> > &) { { 0 }, { 1 }, { 2 }, { 3 } }
2656/// ~~~
2657template <typename T>
2659{
2660 using size_type = typename RVec<T>::size_type;
2661 const size_type s = v.size();
2662 if (n > s) {
2663 throw std::runtime_error("Cannot make unique combinations of size " + std::to_string(n) +
2664 " from vector of size " + std::to_string(s) + ".");
2665 }
2666
2668 for(size_type k=0; k<s; k++)
2669 indices[k] = k;
2670
2671 const auto innersize = [=] {
2672 size_type inners = s - n + 1;
2673 for (size_type m = s - n + 2; m <= s; ++m)
2674 inners *= m;
2675
2676 size_type factn = 1;
2677 for (size_type i = 2; i <= n; ++i)
2678 factn *= i;
2679 inners /= factn;
2680
2681 return inners;
2682 }();
2683
2685 size_type inneridx = 0;
2686 for (size_type k = 0; k < n; k++)
2687 c[k][inneridx] = indices[k];
2688 ++inneridx;
2689
2690 while (true) {
2691 bool run_through = true;
2692 long i = n - 1;
2693 for (; i>=0; i--) {
2694 if (indices[i] != i + s - n){
2695 run_through = false;
2696 break;
2697 }
2698 }
2699 if (run_through) {
2700 return c;
2701 }
2702 indices[i]++;
2703 for (long j=i+1; j<(long)n; j++)
2704 indices[j] = indices[j-1] + 1;
2705 for (size_type k = 0; k < n; k++)
2706 c[k][inneridx] = indices[k];
2707 ++inneridx;
2708 }
2709}
2710
2711/// Return the indices of the elements which are not zero
2712///
2713/// Example code, at the ROOT prompt:
2714/// ~~~{.cpp}
2715/// using namespace ROOT::VecOps;
2716/// RVecD v {2., 0., 3., 0., 1.};
2717/// auto nonzero_idx = Nonzero(v);
2718/// nonzero_idx
2719/// // (ROOT::VecOps::RVec<unsigned long> &) { 0, 2, 4 }
2720/// ~~~
2721template <typename T>
2723{
2724 using size_type = typename RVec<T>::size_type;
2726 const auto size = v.size();
2727 r.reserve(size);
2728 for(size_type i=0; i<size; i++) {
2729 if(v[i] != 0) {
2730 r.emplace_back(i);
2731 }
2732 }
2733 return r;
2734}
2735
2736/// Return the intersection of elements of two RVecs.
2737///
2738/// Each element of v1 is looked up in v2 and added to the returned vector if
2739/// found. Following, the order of v1 is preserved. If v2 is already sorted, the
2740/// optional argument v2_is_sorted can be used to toggle of the internal sorting
2741/// step, therewith optimising runtime.
2742///
2743/// Example code, at the ROOT prompt:
2744/// ~~~{.cpp}
2745/// using namespace ROOT::VecOps;
2746/// RVecD v1 {1., 2., 3.};
2747/// RVecD v2 {-4., -5., 2., 1.};
2748/// auto v1_intersect_v2 = Intersect(v1, v2);
2749/// v1_intersect_v2
2750/// // (ROOT::VecOps::RVec<double> &) { 1.0000000, 2.0000000 }
2751/// ~~~
2752template <typename T>
2753RVec<T> Intersect(const RVec<T>& v1, const RVec<T>& v2, bool v2_is_sorted = false)
2754{
2756 if (!v2_is_sorted) v2_sorted = Sort(v2);
2757 const auto v2_begin = v2_is_sorted ? v2.begin() : v2_sorted.begin();
2758 const auto v2_end = v2_is_sorted ? v2.end() : v2_sorted.end();
2759 RVec<T> r;
2760 const auto size = v1.size();
2761 r.reserve(size);
2762 using size_type = typename RVec<T>::size_type;
2763 for(size_type i=0; i<size; i++) {
2764 if (std::binary_search(v2_begin, v2_end, v1[i])) {
2765 r.emplace_back(v1[i]);
2766 }
2767 }
2768 return r;
2769}
2770
2771/// Return the elements of v1 if the condition c is true and v2 if the
2772/// condition c is false.
2773///
2774/// Example code, at the ROOT prompt:
2775/// ~~~{.cpp}
2776/// using namespace ROOT::VecOps;
2777/// RVecD v1 {1., 2., 3.};
2778/// RVecD v2 {-1., -2., -3.};
2779/// auto c = v1 > 1;
2780/// c
2781/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
2782/// auto if_c_v1_else_v2 = Where(c, v1, v2);
2783/// if_c_v1_else_v2
2784/// // (ROOT::VecOps::RVec<double> &) { -1.0000000, 2.0000000, 3.0000000 }
2785/// ~~~
2786template <typename T>
2787RVec<T> Where(const RVec<int>& c, const RVec<T>& v1, const RVec<T>& v2)
2788{
2789 using size_type = typename RVec<T>::size_type;
2790 const size_type size = c.size();
2791 RVec<T> r;
2792 r.reserve(size);
2793 for (size_type i=0; i<size; i++) {
2794 r.emplace_back(c[i] != 0 ? v1[i] : v2[i]);
2795 }
2796 return r;
2797}
2798
2799/// Return the elements of v1 if the condition c is true and sets the value v2
2800/// if the condition c is false.
2801///
2802/// Example code, at the ROOT prompt:
2803/// ~~~{.cpp}
2804/// using namespace ROOT::VecOps;
2805/// RVecD v1 {1., 2., 3.};
2806/// double v2 = 4.;
2807/// auto c = v1 > 1;
2808/// c
2809/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
2810/// auto if_c_v1_else_v2 = Where(c, v1, v2);
2811/// if_c_v1_else_v2
2812/// // (ROOT::VecOps::RVec<double>) { 4.0000000, 2.0000000, 3.0000000 }
2813/// ~~~
2814template <typename T>
2816{
2817 using size_type = typename RVec<T>::size_type;
2818 const size_type size = c.size();
2819 RVec<T> r;
2820 r.reserve(size);
2821 for (size_type i=0; i<size; i++) {
2822 r.emplace_back(c[i] != 0 ? v1[i] : v2);
2823 }
2824 return r;
2825}
2826
2827/// Return the elements of v2 if the condition c is false and sets the value v1
2828/// if the condition c is true.
2829///
2830/// Example code, at the ROOT prompt:
2831/// ~~~{.cpp}
2832/// using namespace ROOT::VecOps;
2833/// double v1 = 4.;
2834/// RVecD v2 {1., 2., 3.};
2835/// auto c = v2 > 1;
2836/// c
2837/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
2838/// auto if_c_v1_else_v2 = Where(c, v1, v2);
2839/// if_c_v1_else_v2
2840/// // (ROOT::VecOps::RVec<double>) { 1.0000000, 4.0000000, 4.0000000 }
2841/// ~~~
2842template <typename T>
2844{
2845 using size_type = typename RVec<T>::size_type;
2846 const size_type size = c.size();
2847 RVec<T> r;
2848 r.reserve(size);
2849 for (size_type i=0; i<size; i++) {
2850 r.emplace_back(c[i] != 0 ? v1 : v2[i]);
2851 }
2852 return r;
2853}
2854
2855/// Return a vector with the value v2 if the condition c is false and sets the
2856/// value v1 if the condition c is true.
2857///
2858/// Example code, at the ROOT prompt:
2859/// ~~~{.cpp}
2860/// using namespace ROOT::VecOps;
2861/// double v1 = 4.;
2862/// double v2 = 2.;
2863/// RVecI c {0, 1, 1};
2864/// auto if_c_v1_else_v2 = Where(c, v1, v2);
2865/// if_c_v1_else_v2
2866/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 4.0000000, 4.0000000 }
2867/// ~~~
2868template <typename T>
2870{
2871 using size_type = typename RVec<T>::size_type;
2872 const size_type size = c.size();
2873 RVec<T> r;
2874 r.reserve(size);
2875 for (size_type i=0; i<size; i++) {
2876 r.emplace_back(c[i] != 0 ? v1 : v2);
2877 }
2878 return r;
2879}
2880
2881/// Return the concatenation of two RVecs.
2882///
2883/// Example code, at the ROOT prompt:
2884/// ~~~{.cpp}
2885/// using namespace ROOT::VecOps;
2886/// RVecF rvf {0.f, 1.f, 2.f};
2887/// RVecI rvi {7, 8, 9};
2888/// Concatenate(rvf, rvi)
2889/// // (ROOT::VecOps::RVec<float>) { 0.00000f, 1.00000f, 2.00000f, 7.00000f, 8.00000f, 9.00000f }
2890/// ~~~
2893{
2894 RVec<Common_t> res;
2895 res.reserve(v0.size() + v1.size());
2896 std::copy(v0.begin(), v0.end(), std::back_inserter(res));
2897 std::copy(v1.begin(), v1.end(), std::back_inserter(res));
2898 return res;
2899}
2900
2901/// Return the angle difference \f$\Delta \phi\f$ of two scalars.
2902///
2903/// The function computes the closest angle from v1 to v2 with sign and is
2904/// therefore in the range \f$[-\pi, \pi]\f$.
2905/// The computation is done per default in radians \f$c = \pi\f$ but can be switched
2906/// to degrees \f$c = 180\f$.
2907template <typename T0, typename T1 = T0, typename Common_t = std::common_type_t<T0, T1>>
2908Common_t DeltaPhi(T0 v1, T1 v2, const Common_t c = M_PI)
2909{
2910 static_assert(std::is_floating_point<T0>::value && std::is_floating_point<T1>::value,
2911 "DeltaPhi must be called with floating point values.");
2912 auto r = std::fmod(v2 - v1, 2.0 * c);
2913 if (r < -c) {
2914 r += 2.0 * c;
2915 }
2916 else if (r > c) {
2917 r -= 2.0 * c;
2918 }
2919 return r;
2920}
2921
2922/// Return the angle difference \f$\Delta \phi\f$ in radians of two vectors.
2923///
2924/// The function computes the closest angle from v1 to v2 with sign and is
2925/// therefore in the range \f$[-\pi, \pi]\f$.
2926/// The computation is done per default in radians \f$c = \pi\f$ but can be switched
2927/// to degrees \f$c = 180\f$.
2928template <typename T0, typename T1 = T0, typename Common_t = typename std::common_type_t<T0, T1>>
2929RVec<Common_t> DeltaPhi(const RVec<T0>& v1, const RVec<T1>& v2, const Common_t c = M_PI)
2930{
2931 using size_type = typename RVec<T0>::size_type;
2932 const size_type size = v1.size();
2933 auto r = RVec<Common_t>(size);
2934 for (size_type i = 0; i < size; i++) {
2935 r[i] = DeltaPhi(v1[i], v2[i], c);
2936 }
2937 return r;
2938}
2939
2940/// Return the angle difference \f$\Delta \phi\f$ in radians of a vector and a scalar.
2941///
2942/// The function computes the closest angle from v1 to v2 with sign and is
2943/// therefore in the range \f$[-\pi, \pi]\f$.
2944/// The computation is done per default in radians \f$c = \pi\f$ but can be switched
2945/// to degrees \f$c = 180\f$.
2946template <typename T0, typename T1 = T0, typename Common_t = typename std::common_type_t<T0, T1>>
2947RVec<Common_t> DeltaPhi(const RVec<T0>& v1, T1 v2, const Common_t c = M_PI)
2948{
2949 using size_type = typename RVec<T0>::size_type;
2950 const size_type size = v1.size();
2951 auto r = RVec<Common_t>(size);
2952 for (size_type i = 0; i < size; i++) {
2953 r[i] = DeltaPhi(v1[i], v2, c);
2954 }
2955 return r;
2956}
2957
2958/// Return the angle difference \f$\Delta \phi\f$ in radians of a scalar and a vector.
2959///
2960/// The function computes the closest angle from v1 to v2 with sign and is
2961/// therefore in the range \f$[-\pi, \pi]\f$.
2962/// The computation is done per default in radians \f$c = \pi\f$ but can be switched
2963/// to degrees \f$c = 180\f$.
2964template <typename T0, typename T1 = T0, typename Common_t = typename std::common_type_t<T0, T1>>
2965RVec<Common_t> DeltaPhi(T0 v1, const RVec<T1>& v2, const Common_t c = M_PI)
2966{
2967 using size_type = typename RVec<T1>::size_type;
2968 const size_type size = v2.size();
2969 auto r = RVec<Common_t>(size);
2970 for (size_type i = 0; i < size; i++) {
2971 r[i] = DeltaPhi(v1, v2[i], c);
2972 }
2973 return r;
2974}
2975
2976/// Return the square of the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
2977/// the collections eta1, eta2, phi1 and phi2.
2978///
2979/// The function computes \f$\Delta R^2 = (\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2\f$
2980/// of the given collections eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
2981/// be set to radian or degrees using the optional argument c, see the documentation
2982/// of the DeltaPhi helper.
2983template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3>>
2984RVec<Common_t> DeltaR2(const RVec<T0>& eta1, const RVec<T1>& eta2, const RVec<T2>& phi1, const RVec<T3>& phi2, const Common_t c = M_PI)
2985{
2986 const auto dphi = DeltaPhi(phi1, phi2, c);
2987 return (eta1 - eta2) * (eta1 - eta2) + dphi * dphi;
2988}
2989
2990/// Return the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
2991/// the collections eta1, eta2, phi1 and phi2.
2992///
2993/// The function computes \f$\Delta R = \sqrt{(\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2}\f$
2994/// of the given collections eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
2995/// be set to radian or degrees using the optional argument c, see the documentation
2996/// of the DeltaPhi helper.
2997template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3>>
2998RVec<Common_t> DeltaR(const RVec<T0>& eta1, const RVec<T1>& eta2, const RVec<T2>& phi1, const RVec<T3>& phi2, const Common_t c = M_PI)
2999{
3000 return sqrt(DeltaR2(eta1, eta2, phi1, phi2, c));
3001}
3002
3003/// Return the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
3004/// the scalars eta1, eta2, phi1 and phi2.
3005///
3006/// The function computes \f$\Delta R = \sqrt{(\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2}\f$
3007/// of the given scalars eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
3008/// be set to radian or degrees using the optional argument c, see the documentation
3009/// of the DeltaPhi helper.
3010template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3>>
3012{
3013 const auto dphi = DeltaPhi(phi1, phi2, c);
3014 return std::sqrt((eta1 - eta2) * (eta1 - eta2) + dphi * dphi);
3015}
3016
3017/// Return the angle between two three-vectors given the quantities
3018/// x coordinate (x), y coordinate (y), z coordinate (y).
3019///
3020/// The function computes the angle between two three-vectors
3021/// (x1, y2, z1) and (x2, y2, z2).
3022template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename T4 = T0,
3023 typename T5 = T0, typename Common_t = std::common_type_t<T0, T1>>
3024Common_t Angle(T0 x1, T1 y1, T2 z1, T3 x2, T4 y2, T5 z2){
3025 // cross product
3026 const auto cx = y1 * z2 - y2 * z1;
3027 const auto cy = x1 * z2 - x2 * z1;
3028 const auto cz = x1 * y2 - x2 * y1;
3029
3030 // norm of cross product
3031 const auto c = std::sqrt(cx * cx + cy * cy + cz * cz);
3032
3033 // dot product
3034 const auto d = x1 * x2 + y1 * y2 + z1 * z2;
3035
3036 return std::atan2(c, d);
3037}
3038
3039/// Return the invariant mass of two particles given
3040/// x coordinate (px), y coordinate (py), z coordinate (pz) and mass.
3041///
3042/// The function computes the invariant mass of two particles with the four-vectors
3043/// (x1, y2, z1, mass1) and (x2, py2, pz2, mass2).
3044template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename T4 = T0,
3045 typename T5 = T0, typename T6 = T0, typename T7 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3, T4, T5, T6, T7>>
3047 const T0& x1, const T1& y1, const T2& z1, const T3& mass1,
3048 const T4& x2, const T5& y2, const T6& z2, const T7& mass2)
3049{
3050
3051 // Numerically stable computation of Invariant Masses
3052 const auto p1_sq = x1 * x1 + y1 * y1 + z1 * z1;
3053 const auto p2_sq = x2 * x2 + y2 * y2 + z2 * z2;
3054
3055 if (p1_sq <= 0 && p2_sq <= 0)
3056 return (mass1 + mass2);
3057 if (p1_sq <= 0) {
3058 auto mm = mass1 + std::sqrt(mass2*mass2 + p2_sq);
3059 auto m2 = mm*mm - p2_sq;
3060 if (m2 >= 0)
3061 return std::sqrt( m2 );
3062 else
3063 return std::sqrt( -m2 );
3064 }
3065 if (p2_sq <= 0) {
3066 auto mm = mass2 + std::sqrt(mass1*mass1 + p1_sq);
3067 auto m2 = mm*mm - p1_sq;
3068 if (m2 >= 0)
3069 return std::sqrt( m2 );
3070 else
3071 return std::sqrt( -m2 );
3072 }
3073
3074 const auto m1_sq = mass1 * mass1;
3075 const auto m2_sq = mass2 * mass2;
3076
3077 const auto r1 = m1_sq / p1_sq;
3078 const auto r2 = m2_sq / p2_sq;
3079 const auto x = r1 + r2 + r1 * r2;
3080 const auto a = Angle(x1, y1, z1, x2, y2, z2);
3081 const auto cos_a = std::cos(a);
3082 auto y = x;
3083 if ( cos_a >= 0){
3084 y = (x + std::sin(a) * std::sin(a)) / (std::sqrt(x + 1) + cos_a);
3085 } else {
3086 y = std::sqrt(x + 1) - cos_a;
3087 }
3088
3089 const auto z = 2 * std::sqrt(p1_sq * p2_sq);
3090
3091 // Return invariant mass with (+, -, -, -) metric
3092 return std::sqrt(m1_sq + m2_sq + y * z);
3093}
3094
3095/// Return the invariant mass of two particles given the collections of the quantities
3096/// x coordinate (px), y coordinate (py), z coordinate (pz) and mass.
3097///
3098/// The function computes the invariant mass of two particles with the four-vectors
3099/// (px1, py2, pz1, mass1) and (px2, py2, pz2, mass2).
3100template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename T4 = T0,
3101 typename T5 = T0, typename T6 = T0, typename T7 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3, T4, T5, T6, T7>>
3103 const RVec<T0>& px1, const RVec<T1>& py1, const RVec<T2>& pz1, const RVec<T3>& mass1,
3104 const RVec<T4>& px2, const RVec<T5>& py2, const RVec<T6>& pz2, const RVec<T7>& mass2)
3105{
3106 std::size_t size = px1.size();
3107
3108 R__ASSERT(py1.size() == size && pz1.size() == size && mass1.size() == size);
3109 R__ASSERT(px2.size() == size && py2.size() == size && pz2.size() == size && mass2.size() == size);
3110
3112
3113 for (std::size_t i = 0u; i < size; ++i) {
3114 inv_masses[i] = InvariantMasses_PxPyPzM(px1[i], py1[i], pz1[i], mass1[i], px2[i], py2[i], pz2[i], mass2[i]);
3115 }
3116
3117 // Return invariant mass with (+, -, -, -) metric
3118 return inv_masses;
3119}
3120
3121/// Return the invariant mass of two particles given the collections of the quantities
3122/// transverse momentum (pt), rapidity (eta), azimuth (phi) and mass.
3123///
3124/// The function computes the invariant mass of two particles with the four-vectors
3125/// (pt1, eta2, phi1, mass1) and (pt2, eta2, phi2, mass2).
3126template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename T4 = T0,
3127 typename T5 = T0, typename T6 = T0, typename T7 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3, T4, T5, T6, T7>>
3129 const RVec<T0>& pt1, const RVec<T1>& eta1, const RVec<T2>& phi1, const RVec<T3>& mass1,
3130 const RVec<T4>& pt2, const RVec<T5>& eta2, const RVec<T6>& phi2, const RVec<T7>& mass2)
3131{
3132 std::size_t size = pt1.size();
3133
3134 R__ASSERT(eta1.size() == size && phi1.size() == size && mass1.size() == size);
3135 R__ASSERT(pt2.size() == size && phi2.size() == size && mass2.size() == size);
3136
3138
3139 for (std::size_t i = 0u; i < size; ++i) {
3140 // Conversion from (pt, eta, phi, mass) to (x, y, z, mass) coordinate system
3141 const auto x1 = pt1[i] * std::cos(phi1[i]);
3142 const auto y1 = pt1[i] * std::sin(phi1[i]);
3143 const auto z1 = pt1[i] * std::sinh(eta1[i]);
3144
3145 const auto x2 = pt2[i] * std::cos(phi2[i]);
3146 const auto y2 = pt2[i] * std::sin(phi2[i]);
3147 const auto z2 = pt2[i] * std::sinh(eta2[i]);
3148
3149 // Numerically stable computation of Invariant Masses
3150 inv_masses[i] = InvariantMasses_PxPyPzM(x1, y1, z1, mass1[i], x2, y2, z2, mass2[i]);
3151 }
3152
3153 // Return invariant mass with (+, -, -, -) metric
3154 return inv_masses;
3155}
3156
3157/// Return the invariant mass of multiple particles given the collections of the
3158/// quantities transverse momentum (pt), rapidity (eta), azimuth (phi) and mass.
3159///
3160/// The function computes the invariant mass of multiple particles with the
3161/// four-vectors (pt, eta, phi, mass).
3162template <typename T0, typename T1 = T0, typename T2 = T0, typename T3 = T0, typename Common_t = std::common_type_t<T0, T1, T2, T3>>
3163Common_t InvariantMass(const RVec<T0>& pt, const RVec<T1>& eta, const RVec<T2>& phi, const RVec<T3>& mass)
3164{
3165 const std::size_t size = pt.size();
3166
3167 R__ASSERT(eta.size() == size && phi.size() == size && mass.size() == size);
3168
3169 Common_t x_sum = 0.;
3170 Common_t y_sum = 0.;
3171 Common_t z_sum = 0.;
3172 Common_t e_sum = 0.;
3173
3174 for (std::size_t i = 0u; i < size; ++ i) {
3175 // Convert to (e, x, y, z) coordinate system and update sums
3176 const auto x = pt[i] * std::cos(phi[i]);
3177 x_sum += x;
3178 const auto y = pt[i] * std::sin(phi[i]);
3179 y_sum += y;
3180 const auto z = pt[i] * std::sinh(eta[i]);
3181 z_sum += z;
3182 const auto e = std::sqrt(x * x + y * y + z * z + mass[i] * mass[i]);
3183 e_sum += e;
3184 }
3185
3186 // Return invariant mass with (+, -, -, -) metric
3187 return std::sqrt(e_sum * e_sum - x_sum * x_sum - y_sum * y_sum - z_sum * z_sum);
3188}
3189
3190////////////////////////////////////////////////////////////////////////////
3191/// \brief Build an RVec of objects starting from RVecs of input to their constructors.
3192/// \tparam T Type of the objects contained in the created RVec.
3193/// \tparam Args_t Pack of types templating the input RVecs.
3194/// \param[in] args The RVecs containing the values used to initialise the output objects.
3195/// \return The RVec of objects initialised with the input parameters.
3196///
3197/// Example code, at the ROOT prompt:
3198/// ~~~{.cpp}
3199/// using namespace ROOT::VecOps;
3200/// RVecF pts = {15.5, 34.32, 12.95};
3201/// RVecF etas = {0.3, 2.2, 1.32};
3202/// RVecF phis = {0.1, 3.02, 2.2};
3203/// RVecF masses = {105.65, 105.65, 105.65};
3204/// auto fourVecs = Construct<ROOT::Math::PtEtaPhiMVector>(pts, etas, phis, masses);
3205/// cout << fourVecs << endl;
3206/// // { (15.5,0.3,0.1,105.65), (34.32,2.2,3.02,105.65), (12.95,1.32,2.2,105.65) }
3207/// ~~~
3208template <typename T, typename... Args_t>
3210{
3211 const auto size = ::ROOT::Internal::VecOps::GetVectorsSize("Construct", args...);
3212 RVec<T> ret;
3213 ret.reserve(size);
3214 for (auto i = 0UL; i < size; ++i) {
3215 ret.emplace_back(args[i]...);
3216 }
3217 return ret;
3218}
3219
3220/// For any Rvec v produce another RVec with entries starting from 0, and incrementing by 1 until a N = v.size() is reached.
3221/// Example code, at the ROOT prompt:
3222/// ~~~{.cpp}
3223/// using namespace ROOT::VecOps;
3224/// RVecF v = {1., 2., 3.};
3225/// cout << Enumerate(v1) << "\n";
3226/// // { 0, 1, 2 }
3227/// ~~~
3228template <typename T>
3230{
3231 const auto size = v.size();
3232 RVec<T> ret;
3233 ret.reserve(size);
3234 for (auto i = 0UL; i < size; ++i) {
3235 ret.emplace_back(i);
3236 }
3237 return ret;
3238}
3239
3240/**
3241 * \brief Produce RVec with N evenly-spaced entries from start to end.
3242 *
3243 * This function generates a vector of evenly spaced values, starting at \p start and (depending on the
3244 * \p endpoint parameter) either including or excluding \p end. If \p endpoint is true (default),
3245 * the vector contains \p n values with \p end as the final element, and the spacing is computed as
3246 * \f$\text{step} = \frac{\text{end} - \text{start}}{n-1}\f$. If \p endpoint is false,
3247 * the sequence consists of n values computed as if there were n+1 evenly spaced samples, with the final
3248 * value (\p end) omitted; in this case, \f$\text{step} = \frac{\text{end} - \text{start}}{n}\f$.
3249 *
3250 * The function is templated to allow for different return types. The return type \c Ret_t, if
3251 * not explicitly specified, is determined as follows: if \p T is a floating point type, that type is used;
3252 * otherwise, the return type is \c double.
3253 *
3254 * \tparam T Type of the start and end value. Default is double.
3255 * \tparam Ret_t Return type used, which, if not explicitly specified
3256 * in the template, is \p T if that is a floating point type, or double otherwise.
3257 *
3258 * \param start The first value in the sequence.
3259 * \param end The last value in the sequence if \p endpoint is true; otherwise, \p end is excluded.
3260 * \param n The number of evenly spaced entries to produce. The default value is 128, which is different than numpy's default value of 50.
3261 * \param endpoint If true (default), \p end is included as the final element; if false, \p end is excluded.
3262 *
3263 * \return A vector (RVec<Ret_t>) containing \p n evenly spaced values.
3264 *
3265 * \note If \p n is 1, the resulting vector will contain only the value \p start.
3266 * \note The check `if (!n || (n > std::numeric_limits<long long>::max()))` is used to ensure that:
3267 * - division by zero is avoided when calculating `step`
3268 * - n does not exceed std::numeric_limits<long long>::max(), which would indicate that a negative range (or other arithmetic issue)
3269 * has resulted in an extremely large unsigned value, thereby preventing an attempt to reserve an absurd
3270 * amount of memory.
3271 * \note If the template parameter \c Ret_t is explicitly overridden with an integral type, the returned results are rounded towards negative (std::floor) and then cast to the integer type. This is equivalent to setting `dtype = int` in numpy.linspace. To cast to integer without rounding, use instead `RVec<integral_type>(Linspace(...))`, which would be equivalent to `np.linspace(...).astype(integral_type)` in numpy.
3272 *
3273 * \par C++23 Enumerate Support:
3274 * With C++23, you can use the range-based enumerate view to iterate over the resulting vector with both the index
3275 * and the value, similar to Python's `enumerate`. For example:
3276 * ~~~{.cpp}
3277 * for (auto const [index, val] : std::views::enumerate(ROOT::VecOps::Linspace(6, 10, 16))) {
3278 * // Process index and val.
3279 * }
3280 * ~~~
3281 *
3282 * \par Example code, at the ROOT prompt:
3283 * ~~~{.cpp}
3284 * using namespace ROOT::VecOps;
3285 * cout << Linspace(-1, 5, 5) << "\n";
3286 * // { -1, 0.5, 2, 3.5, 5 }
3287 * cout << Linspace(3, 12, 5) << "\n";
3288 * // { 3, 5.25, 7.5, 9.75, 12 }
3289 * cout << Linspace(3, 12, 5, false) << "\n";
3290 * // { 3, 4.8, 6.6, 8.4, 10.2 }
3291 * cout << Linspace<int, int>(1, 10, 3) << "\n";
3292 * // { 1, 5, 10 }
3293 * ~~~
3294 */
3295template <typename T = double, typename Ret_t = std::conditional_t<std::is_floating_point_v<T>, T, double>>
3296inline RVec<Ret_t> Linspace(T start, T end, unsigned long long n = 128, const bool endpoint = true)
3297{
3298 if (!n || (n > std::numeric_limits<long long>::max())) // Check for invalid or absurd n.
3299 {
3300 return {};
3301 }
3302
3303 long double step = std::is_floating_point_v<Ret_t> ?
3304 (end - start) / static_cast<long double>(n - endpoint) :
3305 (end >= start ? static_cast<long double>(end - start) / (n - endpoint) : (static_cast<long double>(end) - start) / (n - endpoint));
3306
3307 RVec<Ret_t> temp(n);
3308 temp[0] = std::is_floating_point_v<Ret_t> ? static_cast<Ret_t>(start) : std::floor(start);
3309 if constexpr (std::is_floating_point_v<Ret_t>)
3310 {
3311 for (unsigned long long i = 1; i < n; i++)
3312 {
3313 temp[i] = static_cast<Ret_t>(start + i * step);
3314 }
3315 }
3316 else
3317 {
3318 for (unsigned long long i = 1; i < n; i++)
3319 {
3320 temp[i] = std::floor(start + i * step);
3321 }
3322 }
3323 return temp;
3324}
3325
3326/**
3327 * \brief Produce RVec with n log-spaced entries from base^{start} to base^{end}.
3328 *
3329 * This function generates a vector of values where the exponents are evenly spaced, and then returns the
3330 * corresponding values of base raised to these exponents. If \p endpoint is true (default), the vector
3331 * contains \p n values with the last element equal to \f$base^{end}\f$. If \p endpoint is false, the
3332 * sequence is computed as if there were n+1 evenly spaced samples over the interval in the exponent space,
3333 * and the final value (\f$base^{end}\f$) is excluded, resulting in a sequence of n values.
3334 *
3335 * The function is templated to allow for different return types. The return type \c Ret_t, if not explicitly specified,
3336 * is determined as follows: if \p T is a floating point type, that type is used; otherwise, the return type is \c double.
3337 *
3338 * \tparam T Type of the start and end exponents and the base. Default is double.
3339 * \tparam Ret_t Deduced type used for return type, which, if not explicitly specified, is \p T if that is a floating point type, or double otherwise.
3340 *
3341 * \param start The exponent corresponding to the first element (i.e., the first element is \f$base^{start}\f$).
3342 * \param end The exponent corresponding to the final element if \p endpoint is true; otherwise, \p end is excluded.
3343 * \param n The number of log-spaced entries to produce. The default value is 128, which is different than numpy's default value of 50.
3344 * \param endpoint If true (default), \f$base^{end}\f$ is included as the final element; if false, \f$base^{end}\f$ is excluded.
3345 * \param base The base to be used in the exponentiation (default is 10.0).
3346 *
3347 * \return A vector (RVec<Ret_t>) containing n log-spaced values.
3348 *
3349 * \note If \p n is 1, the resulting vector will contain only the value \f$base^{start}\f$.
3350 * \note The check `if (!n || (n > std::numeric_limits<long long>::max()))` is used to ensure that:
3351 * - division by zero is avoided when calculating `step`
3352 * - n does not exceed std::numeric_limits<long long>::max(), which would indicate that a negative range (or other arithmetic issue)
3353 * has resulted in an extremely large unsigned value, thereby preventing an attempt to reserve an absurd
3354 * amount of memory.
3355 * \note If the template parameter \c Ret_t is explicitly overridden with an integral type, the returned results are rounded towards negative (`std::floor`) and then cast to the integer type. This is equivalent to setting `dtype = int` in `numpy.linspace`. To cast to integer without rounding, use instead `RVec<integral_type>(Logspace(...))`, which would be equivalent to `np.logspace(...).astype(integral_type)` in numpy.
3356 *
3357 * \par C++23 Enumerate Support:
3358 * With C++23, you can use the range-based enumerate view to iterate over the resulting vector with both the index
3359 * and the value, similar to Python's `enumerate`. For example:
3360 * ~~~{.cpp}
3361 * for (auto const [index, val] : std::views::enumerate(ROOT::VecOps::Logspace(4, 10, 12))) {
3362 * // Process index and val.
3363 * }
3364 * ~~~
3365 *
3366 * \par Example code, at the ROOT prompt:
3367 * ~~~{.cpp}
3368 * using namespace ROOT::VecOps;
3369 * cout << Logspace(4, 10, 12) << '\n';
3370 * // { 10000, 35111.9, 123285, 432876, 1.51991e+06, 5.3367e+06, 1.87382e+07, 6.57933e+07, 2.31013e+08, 8.11131e+08, 2.84804e+09, 1e+10 }
3371 * cout << Logspace(0, 0, 50) << '\n';
3372 * // { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
3373 * cout << Logspace(0, 0, 0) << '\n';
3374 * // { }
3375 * cout << Logspace(4, 10, 12, 10.0, false) << '\n';
3376 * // { 10000, 31622.8, 100000, 316228, 1e+06, 3.16228e+06, 1e+07, 3.16228e+07, 1e+08, 3.16228e+08, 1e+09, 3.16228e+09 }
3377 * cout << Logspace<int, int>(1, 5, 3) << '\n';
3378 * // { 10, 1000, 100000 }
3379 * ~~~
3380 */
3381template <typename T = double, typename Ret_t = std::conditional_t<std::is_floating_point_v<T>, T, double>>
3382inline RVec<Ret_t> Logspace(T start, T end, unsigned long long n = 128, const bool endpoint = true, T base = 10.0)
3383{
3384 if (!n || (n > std::numeric_limits<long long>::max())) // Check for invalid or absurd n.
3385 {
3386 return {};
3387 }
3388 RVec<Ret_t> temp(n);
3389
3390 long double start_c = start;
3391 long double end_c = end;
3392 long double base_c = base;
3393
3394 long double step = (end_c - start_c) / (n - endpoint);
3395
3396 temp[0] = std::is_floating_point_v<Ret_t> ?
3397 static_cast<Ret_t>(std::pow(base_c, start_c)) :
3398 std::floor(std::pow(base_c, start_c));
3399
3400 if constexpr (std::is_floating_point_v<Ret_t>)
3401 {
3402 for (unsigned long long i = 1; i < n; i++)
3403 {
3404 auto exponent = start_c + i * step;
3405 temp[i] = static_cast<Ret_t>(std::pow(base_c, exponent));
3406 }
3407 }
3408 else
3409 {
3410 for (unsigned long long i = 1; i < n; i++)
3411 {
3412 auto exponent = start_c + i * step;
3413 temp[i] = std::floor(std::pow(base_c, exponent));
3414 }
3415 }
3416
3417 return temp;
3418}
3419
3420/**
3421 * \brief Produce RVec with entries in the range [start, end) in increments of step.
3422 *
3423 * This function generates a vector of values starting at \p start and incremented by \p step,
3424 * continuing until the values reach or exceed \p end (the interval is half-open: [start, end)).
3425 * The number of elements is computed as:
3426 * \f[
3427 * n = \lceil \frac{\text{end} - \text{start}}{\text{step}} \rceil
3428 * \f]
3429 * ensuring that the arithmetic is performed in a floating-point context when needed.
3430 *
3431 * The function is templated to allow for different return types. The return type \c Ret_t, if not
3432 * explicitly specified, is determined as follows: if \p T is a floating point type, that type is used;
3433 * otherwise, the return type is \c double.
3434 *
3435 * \tparam T Type of the start, end, and step values. Default is double.
3436 * \tparam Ret_t Return type, which, if not explicitly
3437 * specified, is \p T if that is a floating point type, or double otherwise.
3438 *
3439 * \param start The first value in the range.
3440 * \param end The end of the range (exclusive).
3441 * \param step The increment between consecutive values.
3442 *
3443 * \return A vector (RVec<Ret_t>) containing values starting at \p start, each incremented by \p step,
3444 * up to but not including any value equal to or greater than \p end.
3445 *
3446 * \note The check `if (!n || (n > std::numeric_limits<long long>::max()))` is used to ensure that:
3447 * - n is nonzero, and
3448 * - n does not exceed std::numeric_limits<long long>::max(), which would indicate that a negative range (or other arithmetic issue)
3449 * has resulted in an extremely large unsigned value, thereby preventing an attempt to reserve an absurd
3450 * amount of memory.
3451 * \note If the template parameter \c Ret_t is explicitly overridden with an integral type, the returned results are rounded towards negative (`std::floor`) and then cast to the integer type. This is equivalent to setting `dtype = int` in numpy. To cast to integer without rounding, use instead `RVec<integral_type>(Arange(...))`, which would be equivalent to `np.arange(...).astype(integral_type)` in numpy.
3452 *
3453 * \par C++23 Enumerate Support:
3454 * With C++23, you can use the range-based enumerate view to iterate over the resulting vector with both the index
3455 * and the value, similar to Python's `enumerate`. For example:
3456 * ~~~{.cpp}
3457 * for (auto const [index, val] : std::views::enumerate(ROOT::VecOps::Arange(1, 13, 5))) {
3458 * // Process index and val.
3459 * }
3460 * ~~~
3461 *
3462 * \par Example code, at the ROOT prompt:
3463 * ~~~{.cpp}
3464 * using namespace ROOT::VecOps;
3465 * cout << Arange(0, 0, 5) << '\n';
3466 * // { }
3467 * cout << Arange(-7, 20, 4) << '\n';
3468 * // { -7, -3, 1, 5, 9, 13, 17 }
3469 * cout << Arange(1, 13, 5) << '\n';
3470 * // { 1, 6, 11 }
3471 * cout << Arange<unsigned int, unsigned int>(5, 9, 1) << '\n';
3472 * // { 5, 6, 7, 8 }
3473 * ~~~
3474 */
3475template <typename T = double, typename Ret_t = std::conditional_t<std::is_floating_point_v<T>, T, double>>
3476inline RVec<Ret_t> Arange(T start, T end, T step)
3477{
3478 unsigned long long n = std::ceil(( end >= start ? (end - start) : static_cast<long double>(end)-start)/static_cast<long double>(step)); // Ensure floating-point division.
3479
3480 if (!n || (n > std::numeric_limits<long long>::max())) // Check for invalid or absurd n.
3481 {
3482 return {};
3483 }
3484
3485 RVec<Ret_t> temp(n);
3486
3487 long double start_c = start;
3488 long double step_c = step;
3489
3490 temp[0] = std::is_floating_point_v<Ret_t> ? static_cast<Ret_t>(start) : std::floor(start);
3491 if constexpr (std::is_floating_point_v<Ret_t>)
3492 {
3493 for (unsigned long long i = 1; i < n; i++)
3494 {
3495 temp[i] = static_cast<Ret_t>(start_c + i * step_c);
3496 }
3497 }
3498 else
3499 {
3500 for (unsigned long long i = 1; i < n; i++)
3501 {
3502 temp[i] = std::floor(start_c + i * step_c);
3503 }
3504 }
3505 return temp;
3506}
3507
3508/// Produce RVec with entries starting from 0, and incrementing by 1 until a user-specified N is reached.
3509/// Example code, at the ROOT prompt:
3510/// ~~~{.cpp}
3511/// using namespace ROOT::VecOps;
3512/// cout << Range(3) << "\n";
3513/// // { 0, 1, 2 }
3514/// ~~~
3515inline RVec<std::size_t> Range(std::size_t length)
3516{
3518 ret.reserve(length);
3519 for (auto i = 0UL; i < length; ++i) {
3520 ret.emplace_back(i);
3521 }
3522 return ret;
3523}
3524
3525/// Produce RVec with entries equal to begin, begin+1, ..., end-1.
3526/// An empty RVec is returned if begin >= end.
3527inline RVec<std::size_t> Range(std::size_t begin, std::size_t end)
3528{
3530 ret.reserve(begin < end ? end - begin : 0u);
3531 for (auto i = begin; i < end; ++i)
3532 ret.push_back(i);
3533 return ret;
3534}
3535
3536/// Allows for negative begin, end, and/or stride. Produce RVec<int> with entries equal to begin, begin+stride, ... , N,
3537/// where N is the first integer such that N+stride exceeds or equals N in the positive or negative direction (same as in Python).
3538/// An empty RVec is returned if begin >= end and stride > 0 or if
3539/// begin < end and stride < 0. Throws a runtime_error if stride==0
3540/// Example code, at the ROOT prompt:
3541/// ~~~{.cpp}
3542/// using namespace ROOT::VecOps;
3543/// cout << Range(1, 5, 2) << "\n";
3544/// // { 1, 3 }
3545/// cout << Range(-1, -11, -4) << "\n";
3546/// // { -1, -5, -9 }
3547/// ~~~
3548inline RVec<long long int> Range(long long int begin, long long int end, long long int stride)
3549{
3550 if (stride==0ll)
3551 {
3552 throw std::runtime_error("Range: the stride must not be zero");
3553 }
3555 float ret_cap = std::ceil(static_cast<float>(end-begin) / stride); //the capacity to reserve
3556 //ret_cap < 0 if either begin > end & stride > 0, or begin < end & stride < 0. In both cases, an empty RVec should be returned
3557 if (ret_cap < 0)
3558 {
3559 return ret;
3560 }
3561 ret.reserve(static_cast<size_t>(ret_cap));
3562 if (stride > 0)
3563 {
3564 for (auto i = begin; i < end; i+=stride)
3565 ret.push_back(i);
3566 }
3567 else
3568 {
3569 for (auto i = begin; i > end; i+=stride)
3570 ret.push_back(i);
3571 }
3572 return ret;
3573}
3574
3575
3576
3577////////////////////////////////////////////////////////////////////////////////
3578/// Print a RVec at the prompt:
3579template <class T>
3580std::ostream &operator<<(std::ostream &os, const RVec<T> &v)
3581{
3582 // In order to print properly, convert to 64 bit int if this is a char
3583 constexpr bool mustConvert = std::is_same<char, T>::value || std::is_same<signed char, T>::value ||
3584 std::is_same<unsigned char, T>::value || std::is_same<wchar_t, T>::value ||
3585 std::is_same<char16_t, T>::value || std::is_same<char32_t, T>::value;
3586 using Print_t = typename std::conditional<mustConvert, long long int, T>::type;
3587 os << "{ ";
3588 auto size = v.size();
3589 if (size) {
3590 for (std::size_t i = 0; i < size - 1; ++i) {
3591 os << (Print_t)v[i] << ", ";
3592 }
3593 os << (Print_t)v[size - 1];
3594 }
3595 os << " }";
3596 return os;
3597}
3598
3599#if (_VECOPS_USE_EXTERN_TEMPLATES)
3600
3601#define RVEC_EXTERN_UNARY_OPERATOR(T, OP) \
3602 extern template RVec<T> operator OP<T>(const RVec<T> &);
3603
3604#define RVEC_EXTERN_BINARY_OPERATOR(T, OP) \
3605 extern template auto operator OP<T, T>(const T &x, const RVec<T> &v) \
3606 -> RVec<decltype(x OP v[0])>; \
3607 extern template auto operator OP<T, T>(const RVec<T> &v, const T &y) \
3608 -> RVec<decltype(v[0] OP y)>; \
3609 extern template auto operator OP<T, T>(const RVec<T> &v0, const RVec<T> &v1)\
3610 -> RVec<decltype(v0[0] OP v1[0])>;
3611
3612#define RVEC_EXTERN_ASSIGN_OPERATOR(T, OP) \
3613 extern template RVec<T> &operator OP<T, T>(RVec<T> &, const T &); \
3614 extern template RVec<T> &operator OP<T, T>(RVec<T> &, const RVec<T> &);
3615
3616#define RVEC_EXTERN_LOGICAL_OPERATOR(T, OP) \
3617 extern template RVec<int> operator OP<T, T>(const RVec<T> &, const T &); \
3618 extern template RVec<int> operator OP<T, T>(const T &, const RVec<T> &); \
3619 extern template RVec<int> operator OP<T, T>(const RVec<T> &, const RVec<T> &);
3620
3621#define RVEC_EXTERN_FLOAT_TEMPLATE(T) \
3622 extern template class RVec<T>; \
3623 RVEC_EXTERN_UNARY_OPERATOR(T, +) \
3624 RVEC_EXTERN_UNARY_OPERATOR(T, -) \
3625 RVEC_EXTERN_UNARY_OPERATOR(T, !) \
3626 RVEC_EXTERN_BINARY_OPERATOR(T, +) \
3627 RVEC_EXTERN_BINARY_OPERATOR(T, -) \
3628 RVEC_EXTERN_BINARY_OPERATOR(T, *) \
3629 RVEC_EXTERN_BINARY_OPERATOR(T, /) \
3630 RVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
3631 RVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
3632 RVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
3633 RVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
3634 RVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
3635 RVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
3636 RVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
3637 RVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
3638 RVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
3639 RVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
3640 RVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
3641 RVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
3642
3643#define RVEC_EXTERN_INTEGER_TEMPLATE(T) \
3644 extern template class RVec<T>; \
3645 RVEC_EXTERN_UNARY_OPERATOR(T, +) \
3646 RVEC_EXTERN_UNARY_OPERATOR(T, -) \
3647 RVEC_EXTERN_UNARY_OPERATOR(T, ~) \
3648 RVEC_EXTERN_UNARY_OPERATOR(T, !) \
3649 RVEC_EXTERN_BINARY_OPERATOR(T, +) \
3650 RVEC_EXTERN_BINARY_OPERATOR(T, -) \
3651 RVEC_EXTERN_BINARY_OPERATOR(T, *) \
3652 RVEC_EXTERN_BINARY_OPERATOR(T, /) \
3653 RVEC_EXTERN_BINARY_OPERATOR(T, %) \
3654 RVEC_EXTERN_BINARY_OPERATOR(T, &) \
3655 RVEC_EXTERN_BINARY_OPERATOR(T, |) \
3656 RVEC_EXTERN_BINARY_OPERATOR(T, ^) \
3657 RVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
3658 RVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
3659 RVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
3660 RVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
3661 RVEC_EXTERN_ASSIGN_OPERATOR(T, %=) \
3662 RVEC_EXTERN_ASSIGN_OPERATOR(T, &=) \
3663 RVEC_EXTERN_ASSIGN_OPERATOR(T, |=) \
3664 RVEC_EXTERN_ASSIGN_OPERATOR(T, ^=) \
3665 RVEC_EXTERN_ASSIGN_OPERATOR(T, >>=) \
3666 RVEC_EXTERN_ASSIGN_OPERATOR(T, <<=) \
3667 RVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
3668 RVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
3669 RVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
3670 RVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
3671 RVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
3672 RVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
3673 RVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
3674 RVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
3675
3680//RVEC_EXTERN_INTEGER_TEMPLATE(long long)
3681
3682RVEC_EXTERN_INTEGER_TEMPLATE(unsigned char)
3683RVEC_EXTERN_INTEGER_TEMPLATE(unsigned short)
3684RVEC_EXTERN_INTEGER_TEMPLATE(unsigned int)
3685RVEC_EXTERN_INTEGER_TEMPLATE(unsigned long)
3686//RVEC_EXTERN_INTEGER_TEMPLATE(unsigned long long)
3687
3690
3691#undef RVEC_EXTERN_UNARY_OPERATOR
3692#undef RVEC_EXTERN_BINARY_OPERATOR
3693#undef RVEC_EXTERN_ASSIGN_OPERATOR
3694#undef RVEC_EXTERN_LOGICAL_OPERATOR
3695#undef RVEC_EXTERN_INTEGER_TEMPLATE
3696#undef RVEC_EXTERN_FLOAT_TEMPLATE
3697
3698#define RVEC_EXTERN_UNARY_FUNCTION(T, NAME, FUNC) \
3699 extern template RVec<PromoteType<T>> NAME(const RVec<T> &);
3700
3701#define RVEC_EXTERN_STD_UNARY_FUNCTION(T, F) RVEC_EXTERN_UNARY_FUNCTION(T, F, std::F)
3702
3703#define RVEC_EXTERN_BINARY_FUNCTION(T0, T1, NAME, FUNC) \
3704 extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const T1 &); \
3705 extern template RVec<PromoteTypes<T0, T1>> NAME(const T0 &, const RVec<T1> &); \
3706 extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const RVec<T1> &);
3707
3708#define RVEC_EXTERN_STD_BINARY_FUNCTION(T, F) RVEC_EXTERN_BINARY_FUNCTION(T, T, F, std::F)
3709
3710#define RVEC_EXTERN_STD_FUNCTIONS(T) \
3711 RVEC_EXTERN_STD_UNARY_FUNCTION(T, abs) \
3712 RVEC_EXTERN_STD_BINARY_FUNCTION(T, fdim) \
3713 RVEC_EXTERN_STD_BINARY_FUNCTION(T, fmod) \
3714 RVEC_EXTERN_STD_BINARY_FUNCTION(T, remainder) \
3715 RVEC_EXTERN_STD_UNARY_FUNCTION(T, exp) \
3716 RVEC_EXTERN_STD_UNARY_FUNCTION(T, exp2) \
3717 RVEC_EXTERN_STD_UNARY_FUNCTION(T, expm1) \
3718 RVEC_EXTERN_STD_UNARY_FUNCTION(T, log) \
3719 RVEC_EXTERN_STD_UNARY_FUNCTION(T, log10) \
3720 RVEC_EXTERN_STD_UNARY_FUNCTION(T, log2) \
3721 RVEC_EXTERN_STD_UNARY_FUNCTION(T, log1p) \
3722 RVEC_EXTERN_STD_BINARY_FUNCTION(T, pow) \
3723 RVEC_EXTERN_STD_UNARY_FUNCTION(T, sqrt) \
3724 RVEC_EXTERN_STD_UNARY_FUNCTION(T, cbrt) \
3725 RVEC_EXTERN_STD_BINARY_FUNCTION(T, hypot) \
3726 RVEC_EXTERN_STD_UNARY_FUNCTION(T, sin) \
3727 RVEC_EXTERN_STD_UNARY_FUNCTION(T, cos) \
3728 RVEC_EXTERN_STD_UNARY_FUNCTION(T, tan) \
3729 RVEC_EXTERN_STD_UNARY_FUNCTION(T, asin) \
3730 RVEC_EXTERN_STD_UNARY_FUNCTION(T, acos) \
3731 RVEC_EXTERN_STD_UNARY_FUNCTION(T, atan) \
3732 RVEC_EXTERN_STD_BINARY_FUNCTION(T, atan2) \
3733 RVEC_EXTERN_STD_UNARY_FUNCTION(T, sinh) \
3734 RVEC_EXTERN_STD_UNARY_FUNCTION(T, cosh) \
3735 RVEC_EXTERN_STD_UNARY_FUNCTION(T, tanh) \
3736 RVEC_EXTERN_STD_UNARY_FUNCTION(T, asinh) \
3737 RVEC_EXTERN_STD_UNARY_FUNCTION(T, acosh) \
3738 RVEC_EXTERN_STD_UNARY_FUNCTION(T, atanh) \
3739 RVEC_EXTERN_STD_UNARY_FUNCTION(T, floor) \
3740 RVEC_EXTERN_STD_UNARY_FUNCTION(T, ceil) \
3741 RVEC_EXTERN_STD_UNARY_FUNCTION(T, trunc) \
3742 RVEC_EXTERN_STD_UNARY_FUNCTION(T, round) \
3743 RVEC_EXTERN_STD_UNARY_FUNCTION(T, erf) \
3744 RVEC_EXTERN_STD_UNARY_FUNCTION(T, erfc) \
3745 RVEC_EXTERN_STD_UNARY_FUNCTION(T, lgamma) \
3746 RVEC_EXTERN_STD_UNARY_FUNCTION(T, tgamma) \
3747
3750#undef RVEC_EXTERN_STD_UNARY_FUNCTION
3751#undef RVEC_EXTERN_STD_BINARY_FUNCTION
3752#undef RVEC_EXTERN_STD_UNARY_FUNCTIONS
3753
3754#ifdef R__HAS_VDT
3755
3756#define RVEC_EXTERN_VDT_UNARY_FUNCTION(T, F) RVEC_EXTERN_UNARY_FUNCTION(T, F, vdt::F)
3757
3766
3767RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_exp)
3768RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_log)
3769RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_sin)
3770RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_cos)
3775
3776#endif // R__HAS_VDT
3777
3778#endif // _VECOPS_USE_EXTERN_TEMPLATES
3779
3780/** @} */ // end of Doxygen group vecops
3781
3782} // End of VecOps NS
3783
3784// Allow to use RVec as ROOT::RVec
3785using ROOT::VecOps::RVec;
3786
3797
3798} // End of ROOT NS
3799
3800#endif // ROOT_RVEC
dim_t fSize
#define R__unlikely(expr)
Definition RConfig.hxx:596
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
#define R__RVEC_NODISCARD
Definition RVec.hxx:19
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define M_PI
Definition Rotated.cxx:105
TBuffer & operator<<(TBuffer &buf, const Tmpl *obj)
Definition TBuffer.h:397
#define R__CLING_PTRCHECK(ONOFF)
Definition Rtypes.h:483
static Double_t Product(const Double_t *x, const Float_t *y)
Product.
Definition TCTUB.cxx:100
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
#define N
Double_t Dot(const TGLVector3 &v1, const TGLVector3 &v2)
Definition TGLUtil.h:317
Int_t Compare(const void *item1, const void *item2)
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char y1
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition RVec.hxx:558
void assign(size_type NumElts, const T &Elt)
Definition RVec.hxx:677
typename SuperClass::size_type size_type
Definition RVec.hxx:565
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition RVec.hxx:651
iterator insert(iterator I, T &&Elt)
Definition RVec.hxx:738
void resize(size_type N)
Definition RVec.hxx:593
void assign(std::initializer_list< T > IL)
Definition RVec.hxx:695
void resize(size_type N, const T &NV)
Definition RVec.hxx:608
void reserve(size_type N)
Definition RVec.hxx:622
iterator insert(iterator I, ItTy From, ItTy To)
Definition RVec.hxx:856
reference emplace_back(ArgTypes &&...Args)
Definition RVec.hxx:917
void assign(in_iter in_start, in_iter in_end)
Definition RVec.hxx:689
iterator insert(iterator I, const T &Elt)
Definition RVec.hxx:770
void swap(RVecImpl &RHS)
Definition RVec.hxx:932
iterator insert(iterator I, size_type NumToInsert, const T &Elt)
Definition RVec.hxx:801
RVecImpl & operator=(const RVecImpl &RHS)
Definition RVec.hxx:992
iterator erase(const_iterator CS, const_iterator CE)
Definition RVec.hxx:718
typename SuperClass::reference reference
Definition RVec.hxx:564
void append(size_type NumInputs, const T &Elt)
Append NumInputs copies of Elt to the end.
Definition RVec.hxx:662
iterator erase(const_iterator CI)
Definition RVec.hxx:701
RVecImpl & operator=(RVecImpl &&RHS)
Definition RVec.hxx:1045
void pop_back_n(size_type NumItems)
Definition RVec.hxx:628
RVecImpl(const RVecImpl &)=delete
void append(std::initializer_list< T > IL)
Definition RVec.hxx:671
void insert(iterator I, std::initializer_list< T > IL)
Definition RVec.hxx:914
This is all the stuff common to all SmallVectors.
Definition RVec.hxx:140
SmallVectorBase(void *FirstEl, size_t TotalCapacity)
Definition RVec.hxx:158
static constexpr size_t SizeTypeMax()
The maximum value of the Size_T used.
Definition RVec.hxx:155
Size_T fCapacity
Always >= -1. fCapacity == -1 indicates the RVec is in "memory adoption" mode.
Definition RVec.hxx:152
bool Owns() const
If false, the RVec is in "memory adoption" mode, i.e. it is acting as a view on a memory buffer it do...
Definition RVec.hxx:173
size_t capacity() const noexcept
Definition RVec.hxx:177
void set_size(size_t N)
Set the array size to N, which the current array must have enough capacity for.
Definition RVec.hxx:190
void grow(size_t MinSize=0)
Double the size of the allocated memory, guaranteeing space for at least one more element or MinSize ...
Definition RVec.hxx:474
static void uninitialized_move(It1 I, It1 E, It2 Dest)
Move the range [I, E) onto the uninitialized memory starting with "Dest", constructing elements into ...
Definition RVec.hxx:442
static void uninitialized_copy(T1 *I, T1 *E, T2 *Dest, typename std::enable_if< std::is_same< typename std::remove_const< T1 >::type, T2 >::value >::type *=nullptr)
Copy the range [I, E) onto the uninitialized memory starting with "Dest", constructing elements into ...
Definition RVec.hxx:460
static void uninitialized_copy(It1 I, It1 E, It2 Dest)
Copy the range [I, E) onto the uninitialized memory starting with "Dest", constructing elements into ...
Definition RVec.hxx:451
SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put method implementations that...
Definition RVec.hxx:330
void grow(size_t MinSize=0)
Grow the allocated memory (without initializing new elements), doubling the size of the allocated mem...
static void uninitialized_move(It1 I, It1 E, It2 Dest)
Move the range [I, E) into the uninitialized memory starting with "Dest", constructing elements as ne...
Definition RVec.hxx:345
static void uninitialized_copy(It1 I, It1 E, It2 Dest)
Copy the range [I, E) onto the uninitialized memory starting with "Dest", constructing elements as ne...
Definition RVec.hxx:353
This is the part of SmallVectorTemplateBase which does not depend on whether the type T is a POD.
Definition RVec.hxx:208
const_iterator cbegin() const noexcept
Definition RVec.hxx:263
void grow_pod(size_t MinSize, size_t TSize)
Definition RVec.hxx:224
const_iterator cend() const noexcept
Definition RVec.hxx:266
void resetToSmall()
Put this vector in a state of being small.
Definition RVec.hxx:231
std::reverse_iterator< iterator > reverse_iterator
Definition RVec.hxx:249
bool isSmall() const
Return true if this is a smallvector which has not had dynamic memory allocated for it.
Definition RVec.hxx:228
const_reverse_iterator crend() const noexcept
Definition RVec.hxx:274
const_iterator end() const noexcept
Definition RVec.hxx:265
const_reverse_iterator crbegin() const noexcept
Definition RVec.hxx:271
pointer data() noexcept
Return a pointer to the vector's buffer, even if empty().
Definition RVec.hxx:282
const_reverse_iterator rbegin() const noexcept
Definition RVec.hxx:270
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition RVec.hxx:248
const_iterator begin() const noexcept
Definition RVec.hxx:262
const_pointer data() const noexcept
Return a pointer to the vector's buffer, even if empty().
Definition RVec.hxx:284
void * getFirstEl() const
Find the address of the first element.
Definition RVec.hxx:214
const_reverse_iterator rend() const noexcept
Definition RVec.hxx:273
const_iterator begin() const
const_iterator end() const
RVecN(size_t Size)
Definition RVec.hxx:1162
RVecN(Detail::VecOps::RVecImpl< T > &&RHS)
Definition RVec.hxx:1198
reference operator[](size_type idx)
Definition RVec.hxx:1238
typename Internal::VecOps::SmallVectorTemplateCommon< T >::const_reference const_reference
Definition RVec.hxx:1232
RVecN operator[](const RVecN< V, M > &conds) const
Definition RVec.hxx:1249
RVecN(std::initializer_list< T > IL)
Definition RVec.hxx:1178
const_reference at(size_type pos) const
Definition RVec.hxx:1290
RVecN(const RVecN &RHS)
Definition RVec.hxx:1180
RVecN & operator=(Detail::VecOps::RVecImpl< T > &&RHS)
Definition RVec.hxx:1219
RVecN & operator=(RVecN &&RHS)
Definition RVec.hxx:1206
typename Internal::VecOps::SmallVectorTemplateCommon< T >::size_type size_type
Definition RVec.hxx:1233
value_type at(size_type pos, value_type fallback) const
No exception thrown. The user specifies the desired value in case the RVecN is shorter than pos.
Definition RVec.hxx:1309
RVecN & operator=(std::initializer_list< T > IL)
Definition RVec.hxx:1225
RVecN & operator=(const RVecN &RHS)
Definition RVec.hxx:1186
RVecN(const std::vector< T > &RHS)
Definition RVec.hxx:1204
RVecN(size_t Size, const T &Value)
Definition RVec.hxx:1160
RVecN(RVecN &&RHS)
Definition RVec.hxx:1192
RVecN(ItTy S, ItTy E)
Definition RVec.hxx:1173
reference at(size_type pos)
Definition RVec.hxx:1280
value_type at(size_type pos, value_type fallback)
No exception thrown. The user specifies the desired value in case the RVecN is shorter than pos.
Definition RVec.hxx:1301
RVecN(T *p, size_t n)
Definition RVec.hxx:1212
typename Internal::VecOps::SmallVectorTemplateCommon< T >::reference reference
Definition RVec.hxx:1231
typename Internal::VecOps::SmallVectorTemplateCommon< T >::value_type value_type
Definition RVec.hxx:1234
const_reference operator[](size_type idx) const
Definition RVec.hxx:1243
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1524
RVec(RVecN< T, N > &&RHS)
Definition RVec.hxx:1571
typename SuperClass::reference reference
Definition RVec.hxx:1530
RVec(const RVecN< T, N > &RHS)
Definition RVec.hxx:1574
RVec(size_t Size, const T &Value)
Definition RVec.hxx:1539
RVec(const RVec &RHS)
Definition RVec.hxx:1552
RVec & operator=(RVec &&RHS)
Definition RVec.hxx:1562
RVec(T *p, size_t n)
Definition RVec.hxx:1578
RVec operator[](const RVec< V > &conds) const
Definition RVec.hxx:1590
RVec(std::initializer_list< T > IL)
Definition RVec.hxx:1550
typename SuperClass::const_reference const_reference
Definition RVec.hxx:1531
RVec(size_t Size)
Definition RVec.hxx:1541
RVec(ItTy S, ItTy E)
Definition RVec.hxx:1546
RVec(const std::vector< T > &RHS)
Definition RVec.hxx:1576
typename SuperClass::size_type size_type
Definition RVec.hxx:1532
RVec(Detail::VecOps::RVecImpl< T > &&RHS)
Definition RVec.hxx:1568
RVec(RVec &&RHS)
Definition RVec.hxx:1560
typename SuperClass::value_type value_type
Definition RVec.hxx:1533
RVec & operator=(const RVec &RHS)
Definition RVec.hxx:1554
TPaveText * pt
RVec< T > Reverse(const RVec< T > &v)
Return copy of reversed vector.
Definition RVec.hxx:2476
RVec< T > Intersect(const RVec< T > &v1, const RVec< T > &v2, bool v2_is_sorted=false)
Return the intersection of elements of two RVecs.
Definition RVec.hxx:2753
RVec< typename RVec< T >::size_type > Nonzero(const RVec< T > &v)
Return the indices of the elements which are not zero.
Definition RVec.hxx:2722
#define RVEC_UNARY_OPERATOR(OP)
Definition RVec.hxx:1611
#define RVEC_ASSIGNMENT_OPERATOR(OP)
Definition RVec.hxx:1682
RVec< typename RVec< T >::size_type > StableArgsort(const RVec< T > &v)
Return an RVec of indices that sort the input RVec while keeping the order of equal elements.
Definition RVec.hxx:2290
RVec< Common_t > Concatenate(const RVec< T0 > &v0, const RVec< T1 > &v1)
Return the concatenation of two RVecs.
Definition RVec.hxx:2892
Common_t InvariantMasses_PxPyPzM(const T0 &x1, const T1 &y1, const T2 &z1, const T3 &mass1, const T4 &x2, const T5 &y2, const T6 &z2, const T7 &mass2)
Return the invariant mass of two particles given x coordinate (px), y coordinate (py),...
Definition RVec.hxx:3046
T Sum(const RVec< T > &v, const T zero=T(0))
Sum elements of an RVec.
Definition RVec.hxx:1949
RVec< Common_t > InvariantMasses(const RVec< T0 > &pt1, const RVec< T1 > &eta1, const RVec< T2 > &phi1, const RVec< T3 > &mass1, const RVec< T4 > &pt2, const RVec< T5 > &eta2, const RVec< T6 > &phi2, const RVec< T7 > &mass2)
Return the invariant mass of two particles given the collections of the quantities transverse momentu...
Definition RVec.hxx:3128
RVec< T > Take(const RVec< T > &v, const RVec< typename RVec< T >::size_type > &i)
Return elements of a vector at given indices.
Definition RVec.hxx:2334
void swap(RVec< T > &lhs, RVec< T > &rhs)
Definition RVec.hxx:2228
RVec< T > Construct(const RVec< Args_t > &... args)
Build an RVec of objects starting from RVecs of input to their constructors.
Definition RVec.hxx:3209
#define RVEC_STD_BINARY_FUNCTION(F)
Definition RVec.hxx:1825
#define RVEC_BINARY_OPERATOR(OP)
Definition RVec.hxx:1634
RVec< T > Drop(const RVec< T > &v, RVec< typename RVec< T >::size_type > idxs)
Return a copy of the container without the elements at the specified indices.
Definition RVec.hxx:2443
RVec< Ret_t > Logspace(T start, T end, unsigned long long n=128, const bool endpoint=true, T base=10.0)
Produce RVec with n log-spaced entries from base^{start} to base^{end}.
Definition RVec.hxx:3382
size_t CapacityInBytes(const RVecN< T, N > &X)
Definition RVec.hxx:1603
#define RVEC_LOGICAL_OPERATOR(OP)
Definition RVec.hxx:1718
RVec< RVec< std::size_t > > Combinations(const std::size_t size1, const std::size_t size2)
Return the indices that represent all combinations of the elements of two RVecs.
Definition RVec.hxx:2601
#define RVEC_STD_UNARY_FUNCTION(F)
Definition RVec.hxx:1824
RVec< typename RVec< T >::size_type > Enumerate(const RVec< T > &v)
For any Rvec v produce another RVec with entries starting from 0, and incrementing by 1 until a N = v...
Definition RVec.hxx:3229
auto Map(Args &&... args)
Create new collection applying a callable to the elements of the input collection.
Definition RVec.hxx:2145
RVec< T > Where(const RVec< int > &c, const RVec< T > &v1, const RVec< T > &v2)
Return the elements of v1 if the condition c is true and v2 if the condition c is false.
Definition RVec.hxx:2787
auto Any(const RVec< T > &v) -> decltype(v[0]==true)
Return true if any of the elements equates to true, return false otherwise.
Definition RVec.hxx:2200
RVec< Ret_t > Linspace(T start, T end, unsigned long long n=128, const bool endpoint=true)
Produce RVec with N evenly-spaced entries from start to end.
Definition RVec.hxx:3296
RVec< Ret_t > Arange(T start, T end, T step)
Produce RVec with entries in the range [start, end) in increments of step.
Definition RVec.hxx:3476
RVec< typename RVec< T >::size_type > Argsort(const RVec< T > &v)
Return an RVec of indices that sort the input RVec.
Definition RVec.hxx:2245
std::size_t ArgMin(const RVec< T > &v)
Get the index of the smallest element of an RVec In case of multiple occurrences of the minimum value...
Definition RVec.hxx:2080
RVec< T > StableSort(const RVec< T > &v)
Return copy of RVec with elements sorted in ascending order while keeping the order of equal elements...
Definition RVec.hxx:2546
RVec< T > Filter(const RVec< T > &v, F &&f)
Create a new collection with the elements passing the filter expressed by the predicate.
Definition RVec.hxx:2177
std::size_t ArgMax(const RVec< T > &v)
Get the index of the greatest element of an RVec In case of multiple occurrences of the maximum value...
Definition RVec.hxx:2062
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
#define T2
Definition md5.inl:147
#define T7
Definition md5.inl:152
#define T6
Definition md5.inl:151
#define T3
Definition md5.inl:148
#define T5
Definition md5.inl:150
#define T4
Definition md5.inl:149
#define F(x, y, z)
#define I(x, y, z)
#define T1
Definition md5.inl:146
bool IsSmall(const ROOT::VecOps::RVec< T > &v)
Definition RVec.hxx:1115
bool IsAdopting(const ROOT::VecOps::RVec< T > &v)
Definition RVec.hxx:1121
auto MapImpl(F &&f, RVecs &&... vs) -> RVec< decltype(f(vs[0]...))>
Definition RVec.hxx:107
void ResetView(RVec< T > &v, T *addr, std::size_t sz)
An unsafe function to reset the buffer for which this RVec is acting as a view.
Definition RVec.hxx:543
uint64_t NextPowerOf2(uint64_t A)
Return the next power of two (in 64-bits) that is strictly greater than A.
Definition RVec.hxx:128
constexpr bool All(const bool *vals, std::size_t size)
Definition RVec.hxx:81
std::size_t GetVectorsSize(const std::string &id, const RVec< T > &... vs)
Definition RVec.hxx:90
void UninitializedValueConstruct(ForwardIt first, ForwardIt last)
Definition RVec.hxx:527
auto MapFromTuple(Tuple_t &&t, std::index_sequence< Is... >) -> decltype(MapImpl(std::get< std::tuple_size< Tuple_t >::value - 1 >(t), std::get< Is >(t)...))
Definition RVec.hxx:119
The size of the inline storage of an RVec.
Definition RVec.hxx:514
Used to figure out the offset of the first element of an RVec.
Definition RVec.hxx:201
Storage for the SmallVector elements.
Definition RVec.hxx:499
Ta Range(0, 0, 1, 1)
TMarker m
Definition textangle.C:8