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