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