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