This document is meant for ROOT developers, to quickly get their bearings around the VecOps library.
The main type in the library is RVec
. Besides RVec
, the library only contains helper types and functions.
RVec
is a vector type that tries to be as std::vector
-like as possible while adding a few important features, namely:
operator[](mask)
to allow quick element selection together with vectorized operators (e.g. etas[etas > k]
returns a new RVec
with all elements greater than k
)InvariantMass
, DeltaR
, Argsort
are also providedThe current implementation of RVec
is based on LLVM's SmallVector, extracted from the head of LLVM's repo around December 2020. We are not tracking the upstream implementation.
Compared to LLVM's SmallVectors:
using
declarations had to be lowered in the inheritance hierarchy for cppyy to pick them up)operator[](mask)
has been added, as well as several other "numpy-like" helper functions (these latter ones are free functions)==
, <
, >
etc. return vectors rather than booleansstd::vector
with a custom allocator) and to make the code more consistent with ROOT's coding conventionsSmallVectorBase
fBeginX
fSize
fCapacity
Basically the same as the corresponding LLVM class, with the template parameter removed: LLVM's SmallVectorBase is templated over the type of fSize and fCapacity. It contains the parts of RVec
that do not depend on the value type. No other classes in the hierarchy can contain data members! We expect the memory after SmallVectorBase
to be occupied by the small inline buffer.
SmallVectorTemplateCommon<T>
getFirstEl()
: returns the address of the beginning of the small bufferbegin()
, end()
, front()
, back()
, etc.Basically the same as the corresponding LLVM class. It contains the parts that are independent of whether T is a POD or not.
SmallVectorTemplateBase<T, bool TriviallyCopiable>
and the specialization SmallVectorTemplateBase<T, true>
grow()
, uninitialized_copy
, uninitialized_move
, push_back()
, pop_back()
This class contains the parts of RVec
that can be optimized for trivially copiable types. In particular, destruction can be skipped and memcpy can be used in place of copy/move construction. These optimizations are inherited from LLVM's SmallVector.
RVecImpl<T>
The analogous of LLVM's SmallVectorImpl
, it factors out of RVec
the parts that are independent of the small buffer size, to limit the amount of code generated and provide a way to slice the small buffer size when passing around RVec
objects.
RVecN<T, N>
It aggregates RVecImpl
and SmallVectorStorage
(see below) through public inheritance. N
is the small buffer size.
RVec<T>
Inherits from RVecN
and fixes the small buffer size N
to a reasonable default. We expect most users to use this type and only very rarely switch to RVecN
to tweak the small buffer size.
SmallVectorAlignmentAndSize
: used to figure out the offset of the first small-buffer element in SmallVectorTemplateCommon::getFirstEl
SmallVectorStorage
: properly aligned "small buffer" storage. It's a separate type so that it can be specialized to be properly aligned also for the case of small buffer size = 0RVecInlineStorageSize
: calculates the size of the small buffer in RVec
.We need RVec to be able to act as a view over an existing buffer rather than use its own to save copies and allocations when reading ROOT data into RVec
s, e.g. in RDataFrame
.
The feature is exposed via a dedicated constructor: RVec(pointer, size)
. RVec
then switches to its own storage as soon as a resize is requested. fCapacity == -1
indicates that we are in "memory adoption mode".
As per its docs, LLVM's SmallVector
implementation "does not attempt to be exception-safe". In its current implementation, RVec
does not attempt to fix that. This should not be a problem for RVec
's usecases (an exception thrown during construction of an RVec
typically means there is a bug to fix in the analysis code), and we expect to be able to revisit the implementation and fix broken behavior if it ever turns out to be problematic.
Relevant discussion on GitHub: