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