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