Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:14:20

0001 /// \file ROOT/RField/Fundamental.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2018-10-09
0005 
0006 /*************************************************************************
0007  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0008  * All rights reserved.                                                  *
0009  *                                                                       *
0010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0012  *************************************************************************/
0013 
0014 #ifndef ROOT_RField_Fundamental
0015 #define ROOT_RField_Fundamental
0016 
0017 #ifndef ROOT_RField
0018 #error "Please include RField.hxx!"
0019 #endif
0020 
0021 #include <ROOT/RColumn.hxx>
0022 #include <ROOT/RFieldBase.hxx>
0023 #include <ROOT/RNTupleUtil.hxx>
0024 
0025 #include <cstddef>
0026 #include <memory>
0027 #include <string>
0028 #include <string_view>
0029 #include <type_traits>
0030 
0031 namespace ROOT {
0032 namespace Experimental {
0033 
0034 namespace Detail {
0035 class RFieldVisitor;
0036 } // namespace Detail
0037 
0038 } // namespace Experimental
0039 
0040 ////////////////////////////////////////////////////////////////////////////////
0041 /// Template specializations for concrete C++ fundamental types
0042 ////////////////////////////////////////////////////////////////////////////////
0043 
0044 template <>
0045 class RField<void> : public RFieldBase {
0046 public:
0047    static std::string TypeName() { return "void"; }
0048    // RField<void> should never be constructed.
0049    RField() = delete;
0050    RField(const RField &) = delete;
0051    RField &operator=(const RField &) = delete;
0052 };
0053 
0054 ////////////////////////////////////////////////////////////////////////////////
0055 /// Template specializations for integral types
0056 ////////////////////////////////////////////////////////////////////////////////
0057 
0058 // bool and char are somewhat special, handle them first
0059 
0060 extern template class RSimpleField<bool>;
0061 
0062 template <>
0063 class RField<bool> final : public RSimpleField<bool> {
0064 protected:
0065    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0066    {
0067       return std::make_unique<RField>(newName);
0068    }
0069 
0070    const RColumnRepresentations &GetColumnRepresentations() const final;
0071 
0072 public:
0073    static std::string TypeName() { return "bool"; }
0074    explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
0075    RField(RField &&other) = default;
0076    RField &operator=(RField &&other) = default;
0077    ~RField() final = default;
0078 
0079    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0080 };
0081 
0082 extern template class RSimpleField<char>;
0083 
0084 template <>
0085 class RField<char> final : public RSimpleField<char> {
0086 protected:
0087    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0088    {
0089       return std::make_unique<RField>(newName);
0090    }
0091 
0092    const RColumnRepresentations &GetColumnRepresentations() const final;
0093 
0094 public:
0095    static std::string TypeName() { return "char"; }
0096    explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
0097    RField(RField &&other) = default;
0098    RField &operator=(RField &&other) = default;
0099    ~RField() final = default;
0100 
0101    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0102 };
0103 
0104 // For other integral types, we introduce an intermediate RIntegralField. It is specialized for fixed-width integer
0105 // types (from std::[u]int8_t to std::[u]int64_t). RField<T> for integral types T is specialized by mapping to the
0106 // corresponding fixed-width integer type (see RIntegralTypeMap).
0107 
0108 template <typename T>
0109 class RIntegralField {
0110    // Instantiating this base template definition should never happen and is an error!
0111    RIntegralField() = delete;
0112 };
0113 
0114 extern template class RSimpleField<std::int8_t>;
0115 
0116 template <>
0117 class RIntegralField<std::int8_t> : public RSimpleField<std::int8_t> {
0118 protected:
0119    const RColumnRepresentations &GetColumnRepresentations() const final;
0120 
0121 public:
0122    static std::string TypeName() { return "std::int8_t"; }
0123    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0124    RIntegralField(RIntegralField &&other) = default;
0125    RIntegralField &operator=(RIntegralField &&other) = default;
0126    ~RIntegralField() override = default;
0127 
0128    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0129 };
0130 
0131 extern template class RSimpleField<std::uint8_t>;
0132 
0133 template <>
0134 class RIntegralField<std::uint8_t> : public RSimpleField<std::uint8_t> {
0135 protected:
0136    const RColumnRepresentations &GetColumnRepresentations() const final;
0137 
0138 public:
0139    static std::string TypeName() { return "std::uint8_t"; }
0140    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0141    RIntegralField(RIntegralField &&other) = default;
0142    RIntegralField &operator=(RIntegralField &&other) = default;
0143    ~RIntegralField() override = default;
0144 
0145    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0146 };
0147 
0148 extern template class RSimpleField<std::int16_t>;
0149 
0150 template <>
0151 class RIntegralField<std::int16_t> : public RSimpleField<std::int16_t> {
0152 protected:
0153    const RColumnRepresentations &GetColumnRepresentations() const final;
0154 
0155 public:
0156    static std::string TypeName() { return "std::int16_t"; }
0157    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0158    RIntegralField(RIntegralField &&other) = default;
0159    RIntegralField &operator=(RIntegralField &&other) = default;
0160    ~RIntegralField() override = default;
0161 
0162    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0163 };
0164 
0165 extern template class RSimpleField<std::uint16_t>;
0166 
0167 template <>
0168 class RIntegralField<std::uint16_t> : public RSimpleField<std::uint16_t> {
0169 protected:
0170    const RColumnRepresentations &GetColumnRepresentations() const final;
0171 
0172 public:
0173    static std::string TypeName() { return "std::uint16_t"; }
0174    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0175    RIntegralField(RIntegralField &&other) = default;
0176    RIntegralField &operator=(RIntegralField &&other) = default;
0177    ~RIntegralField() override = default;
0178 
0179    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0180 };
0181 
0182 extern template class RSimpleField<std::int32_t>;
0183 
0184 template <>
0185 class RIntegralField<std::int32_t> : public RSimpleField<std::int32_t> {
0186 protected:
0187    const RColumnRepresentations &GetColumnRepresentations() const final;
0188 
0189 public:
0190    static std::string TypeName() { return "std::int32_t"; }
0191    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0192    RIntegralField(RIntegralField &&other) = default;
0193    RIntegralField &operator=(RIntegralField &&other) = default;
0194    ~RIntegralField() override = default;
0195 
0196    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0197 };
0198 
0199 extern template class RSimpleField<std::uint32_t>;
0200 
0201 template <>
0202 class RIntegralField<std::uint32_t> : public RSimpleField<std::uint32_t> {
0203 protected:
0204    const RColumnRepresentations &GetColumnRepresentations() const final;
0205 
0206 public:
0207    static std::string TypeName() { return "std::uint32_t"; }
0208    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0209    RIntegralField(RIntegralField &&other) = default;
0210    RIntegralField &operator=(RIntegralField &&other) = default;
0211    ~RIntegralField() override = default;
0212 
0213    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0214 };
0215 
0216 extern template class RSimpleField<std::int64_t>;
0217 
0218 template <>
0219 class RIntegralField<std::int64_t> : public RSimpleField<std::int64_t> {
0220 protected:
0221    const RColumnRepresentations &GetColumnRepresentations() const final;
0222 
0223 public:
0224    static std::string TypeName() { return "std::int64_t"; }
0225    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0226    RIntegralField(RIntegralField &&other) = default;
0227    RIntegralField &operator=(RIntegralField &&other) = default;
0228    ~RIntegralField() override = default;
0229 
0230    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0231 };
0232 
0233 extern template class RSimpleField<std::uint64_t>;
0234 
0235 template <>
0236 class RIntegralField<std::uint64_t> : public RSimpleField<std::uint64_t> {
0237 protected:
0238    const RColumnRepresentations &GetColumnRepresentations() const final;
0239 
0240 public:
0241    static std::string TypeName() { return "std::uint64_t"; }
0242    explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
0243    RIntegralField(RIntegralField &&other) = default;
0244    RIntegralField &operator=(RIntegralField &&other) = default;
0245    ~RIntegralField() override = default;
0246 
0247    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0248 };
0249 
0250 namespace Internal {
0251 // Map standard integer types to fixed width equivalents.
0252 template <typename T>
0253 struct RIntegralTypeMap {
0254    using type = T;
0255 };
0256 
0257 // RField<char> has its own specialization, we should not need a specialization of RIntegralTypeMap.
0258 // From https://en.cppreference.com/w/cpp/language/types:
0259 // char has the same representation and alignment as either signed char or
0260 // unsigned char, but is always a distinct type.
0261 template <>
0262 struct RIntegralTypeMap<signed char> {
0263    static_assert(sizeof(signed char) == sizeof(std::int8_t));
0264    using type = std::int8_t;
0265 };
0266 template <>
0267 struct RIntegralTypeMap<unsigned char> {
0268    static_assert(sizeof(unsigned char) == sizeof(std::uint8_t));
0269    using type = std::uint8_t;
0270 };
0271 template <>
0272 struct RIntegralTypeMap<short> {
0273    static_assert(sizeof(short) == sizeof(std::int16_t));
0274    using type = std::int16_t;
0275 };
0276 template <>
0277 struct RIntegralTypeMap<unsigned short> {
0278    static_assert(sizeof(unsigned short) == sizeof(std::uint16_t));
0279    using type = std::uint16_t;
0280 };
0281 template <>
0282 struct RIntegralTypeMap<int> {
0283    static_assert(sizeof(int) == sizeof(std::int32_t));
0284    using type = std::int32_t;
0285 };
0286 template <>
0287 struct RIntegralTypeMap<unsigned int> {
0288    static_assert(sizeof(unsigned int) == sizeof(std::uint32_t));
0289    using type = std::uint32_t;
0290 };
0291 template <>
0292 struct RIntegralTypeMap<long> {
0293    static_assert(sizeof(long) == sizeof(std::int32_t) || sizeof(long) == sizeof(std::int64_t));
0294    using type = std::conditional_t<sizeof(long) == sizeof(std::int32_t), std::int32_t, std::int64_t>;
0295 };
0296 template <>
0297 struct RIntegralTypeMap<unsigned long> {
0298    static_assert(sizeof(unsigned long) == sizeof(std::uint32_t) || sizeof(unsigned long) == sizeof(std::uint64_t));
0299    using type = std::conditional_t<sizeof(unsigned long) == sizeof(std::uint32_t), std::uint32_t, std::uint64_t>;
0300 };
0301 template <>
0302 struct RIntegralTypeMap<long long> {
0303    static_assert(sizeof(long long) == sizeof(std::int64_t));
0304    using type = std::int64_t;
0305 };
0306 template <>
0307 struct RIntegralTypeMap<unsigned long long> {
0308    static_assert(sizeof(unsigned long long) == sizeof(std::uint64_t));
0309    using type = std::uint64_t;
0310 };
0311 } // namespace Internal
0312 
0313 template <typename T>
0314 class RField<T, typename std::enable_if<std::is_integral_v<T>>::type> final
0315    : public RIntegralField<typename Internal::RIntegralTypeMap<T>::type> {
0316    using MappedType = typename Internal::RIntegralTypeMap<T>::type;
0317    static_assert(sizeof(T) == sizeof(MappedType), "invalid size of mapped type");
0318    static_assert(std::is_signed_v<T> == std::is_signed_v<MappedType>, "invalid signedness of mapped type");
0319    using BaseType = RIntegralField<MappedType>;
0320 
0321 protected:
0322    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0323    {
0324       return std::make_unique<RField>(newName);
0325    }
0326 
0327 public:
0328    RField(std::string_view name) : RIntegralField<MappedType>(name) {}
0329    RField(RField &&other) = default;
0330    RField &operator=(RField &&other) = default;
0331    ~RField() final = default;
0332 
0333    T *Map(ROOT::NTupleSize_t globalIndex) { return reinterpret_cast<T *>(this->BaseType::Map(globalIndex)); }
0334    T *Map(RNTupleLocalIndex localIndex) { return reinterpret_cast<T *>(this->BaseType::Map(localIndex)); }
0335    T *MapV(ROOT::NTupleSize_t globalIndex, ROOT::NTupleSize_t &nItems)
0336    {
0337       return reinterpret_cast<T *>(this->BaseType::MapV(globalIndex, nItems));
0338    }
0339    T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
0340    {
0341       return reinterpret_cast<T *>(this->BaseType::MapV(localIndex, nItems));
0342    }
0343 };
0344 
0345 ////////////////////////////////////////////////////////////////////////////////
0346 /// Template specializations for floating-point types
0347 ////////////////////////////////////////////////////////////////////////////////
0348 
0349 extern template class RSimpleField<double>;
0350 extern template class RSimpleField<float>;
0351 
0352 template <typename T>
0353 class RRealField : public RSimpleField<T> {
0354    using Base = RSimpleField<T>;
0355 
0356    using Base::fAvailableColumns;
0357    using Base::fColumnRepresentatives;
0358    using Base::fPrincipalColumn;
0359 
0360    std::size_t fBitWidth = sizeof(T) * 8;
0361    double fValueMin = std::numeric_limits<T>::min();
0362    double fValueMax = std::numeric_limits<T>::max();
0363 
0364 protected:
0365    /// Called by derived fields' CloneImpl()
0366    RRealField(std::string_view name, const RRealField &source)
0367       : RSimpleField<T>(name, source.GetTypeName()),
0368         fBitWidth(source.fBitWidth),
0369         fValueMin(source.fValueMin),
0370         fValueMax(source.fValueMax)
0371    {
0372    }
0373 
0374    void GenerateColumns() final
0375    {
0376       const auto r = Base::GetColumnRepresentatives();
0377       const auto n = r.size();
0378       fAvailableColumns.reserve(n);
0379       for (std::uint16_t i = 0; i < n; ++i) {
0380          auto &column = fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(r[i][0], 0, i));
0381          if (r[i][0] == ROOT::ENTupleColumnType::kReal32Trunc) {
0382             column->SetBitsOnStorage(fBitWidth);
0383          } else if (r[i][0] == ROOT::ENTupleColumnType::kReal32Quant) {
0384             column->SetBitsOnStorage(fBitWidth);
0385             column->SetValueRange(fValueMin, fValueMax);
0386          }
0387       }
0388       fPrincipalColumn = fAvailableColumns[0].get();
0389    }
0390 
0391    void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final
0392    {
0393       std::uint16_t representationIndex = 0;
0394       do {
0395          const auto &onDiskTypes = Base::EnsureCompatibleColumnTypes(desc, representationIndex);
0396          if (onDiskTypes.empty())
0397             break;
0398 
0399          auto &column =
0400             fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(onDiskTypes[0], 0, representationIndex));
0401          if (onDiskTypes[0] == ROOT::ENTupleColumnType::kReal32Trunc) {
0402             const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
0403             const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
0404             column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
0405          } else if (onDiskTypes[0] == ROOT::ENTupleColumnType::kReal32Quant) {
0406             const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
0407             const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
0408             assert(coldesc.GetValueRange().has_value());
0409             const auto [valMin, valMax] = *coldesc.GetValueRange();
0410             column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
0411             column->SetValueRange(valMin, valMax);
0412          }
0413          fColumnRepresentatives.emplace_back(onDiskTypes);
0414          if (representationIndex > 0) {
0415             fAvailableColumns[0]->MergeTeams(*fAvailableColumns[representationIndex]);
0416          }
0417 
0418          representationIndex++;
0419       } while (true);
0420       fPrincipalColumn = fAvailableColumns[0].get();
0421    }
0422 
0423    ~RRealField() override = default;
0424 
0425 public:
0426    using Base::SetColumnRepresentatives;
0427 
0428    RRealField(std::string_view name, std::string_view typeName) : RSimpleField<T>(name, typeName) {}
0429    RRealField(RRealField &&other) = default;
0430    RRealField &operator=(RRealField &&other) = default;
0431 
0432    /// Sets this field to use a half precision representation, occupying half as much storage space (16 bits:
0433    /// 1 sign bit, 5 exponent bits, 10 mantissa bits) on disk.
0434    /// This is mutually exclusive with SetTruncated() and SetQuantized() and supersedes them if called after them.
0435    void SetHalfPrecision() { SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal16}}); }
0436 
0437    /// Set the on-disk representation of this field to a single-precision float truncated to `nBits`.
0438    /// The remaining (32 - `nBits`) bits will be truncated from the number's mantissa.
0439    /// `nBits` must be $10 <= nBits <= 31$ (this means that at least 1 bit
0440    /// of mantissa is always preserved). Note that this effectively rounds the number towards 0.
0441    /// For a double-precision field, this implies first a cast to single-precision, then the truncation.
0442    /// This is mutually exclusive with SetHalfPrecision() and SetQuantized() and supersedes them if called after them.
0443    void SetTruncated(std::size_t nBits)
0444    {
0445       const auto &[minBits, maxBits] =
0446          ROOT::Internal::RColumnElementBase::GetValidBitRange(ROOT::ENTupleColumnType::kReal32Trunc);
0447       if (nBits < minBits || nBits > maxBits) {
0448          throw RException(R__FAIL("SetTruncated() argument nBits = " + std::to_string(nBits) +
0449                                   " is out of valid range [" + std::to_string(minBits) + ", " +
0450                                   std::to_string(maxBits) + "])"));
0451       }
0452       SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Trunc}});
0453       fBitWidth = nBits;
0454    }
0455 
0456    /// Sets this field to use a quantized integer representation using `nBits` per value.
0457    /// It must be $1 <= nBits <= 32$.
0458    /// `minValue` and `maxValue` must not be infinity, `NaN` or denormal floats.
0459    /// Calling this function establishes a promise by the caller to RNTuple that this field will only contain values
0460    /// contained in `[minValue, maxValue]` inclusive. If a value outside this range is assigned to this field, the
0461    /// behavior is undefined.
0462    /// This is mutually exclusive with SetTruncated() and SetHalfPrecision() and supersedes them if called after them.
0463    void SetQuantized(T minValue, T maxValue, std::size_t nBits)
0464    {
0465       const auto &[minBits, maxBits] =
0466          ROOT::Internal::RColumnElementBase::GetValidBitRange(ROOT::ENTupleColumnType::kReal32Quant);
0467       if (nBits < minBits || nBits > maxBits) {
0468          throw RException(R__FAIL("SetQuantized() argument nBits = " + std::to_string(nBits) +
0469                                   " is out of valid range [" + std::to_string(minBits) + ", " +
0470                                   std::to_string(maxBits) + "])"));
0471       }
0472       SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Quant}});
0473       fBitWidth = nBits;
0474       fValueMin = minValue;
0475       fValueMax = maxValue;
0476    }
0477 };
0478 
0479 template <>
0480 class RField<float> final : public RRealField<float> {
0481    const RColumnRepresentations &GetColumnRepresentations() const final;
0482 
0483    RField(std::string_view name, const RField &source) : RRealField<float>(name, source) {}
0484 
0485    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0486    {
0487       return std::unique_ptr<RField>(new RField(newName, *this));
0488    }
0489 
0490 public:
0491    static std::string TypeName() { return "float"; }
0492 
0493    explicit RField(std::string_view name) : RRealField<float>(name, TypeName()) {}
0494 
0495    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0496 };
0497 
0498 template <>
0499 class RField<double> final : public RRealField<double> {
0500    const RColumnRepresentations &GetColumnRepresentations() const final;
0501 
0502    RField(std::string_view name, const RField &source) : RRealField<double>(name, source) {}
0503 
0504    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0505    {
0506       return std::unique_ptr<RField>(new RField(newName, *this));
0507    }
0508 
0509 public:
0510    static std::string TypeName() { return "double"; }
0511 
0512    explicit RField(std::string_view name) : RRealField<double>(name, TypeName()) {}
0513 
0514    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0515 
0516    // Set the column representation to 32 bit floating point and the type alias to `Double32_t`
0517    void SetDouble32();
0518 };
0519 
0520 } // namespace ROOT
0521 
0522 #endif