Logo ROOT  
Reference Guide
RColumnElement.hxx
Go to the documentation of this file.
1/// \file ROOT/RColumnElement.hxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RColumnElement
17#define ROOT7_RColumnElement
18
19#include <ROOT/RColumnModel.hxx>
20#include <ROOT/RConfig.hxx>
21#include <ROOT/RNTupleUtil.hxx>
22
23#include <Byteswap.h>
24#include <TError.h>
25
26#include <cstring> // for memcpy
27#include <cstdint>
28#include <memory>
29#include <string>
30#include <type_traits>
31
32#ifndef R__LITTLE_ENDIAN
33#ifdef R__BYTESWAP
34// `R__BYTESWAP` is defined in RConfig.hxx for little-endian architectures; undefined otherwise
35#define R__LITTLE_ENDIAN 1
36#else
37#define R__LITTLE_ENDIAN 0
38#endif
39#endif /* R__LITTLE_ENDIAN */
40
41namespace {
42/// \brief Copy and byteswap `count` elements of size `N` from `source` to `destination`.
43///
44/// Used on big-endian architectures for packing/unpacking elements whose column type requires
45/// a little-endian on-disk representation.
46template <std::size_t N>
47static void CopyElementsBswap(void *destination, const void *source, std::size_t count)
48{
49 auto dst = reinterpret_cast<typename RByteSwap<N>::value_type *>(destination);
50 auto src = reinterpret_cast<const typename RByteSwap<N>::value_type *>(source);
51 for (std::size_t i = 0; i < count; ++i) {
52 dst[i] = RByteSwap<N>::bswap(src[i]);
53 }
54}
55} // anonymous namespace
56
57namespace ROOT {
58namespace Experimental {
59
60namespace Detail {
61
62// clang-format off
63/**
64\class ROOT::Experimental::Detail::RColumnElement
65\ingroup NTuple
66\brief A column element points either to the content of an RFieldValue or into a memory mapped page.
67
68The content pointed to by fRawContent can be a single element or the first element of an array.
69Usually the on-disk element should map bitwise to the in-memory element. Sometimes that's not the case
70though, for instance on big endian platforms and for exotic physical columns like 8 bit float.
71
72This class does not provide protection around the raw pointer, fRawContent has to be managed correctly
73by the user of this class.
74*/
75// clang-format on
77protected:
78 /// Points to valid C++ data, either a single value or an array of values
80 /// Size of the C++ value pointed to by fRawContent (not necessarily equal to the on-disk element size)
81 std::size_t fSize;
82
83public:
85 : fRawContent(nullptr)
86 , fSize(0)
87 {}
88 RColumnElementBase(void *rawContent, std::size_t size) : fRawContent(rawContent), fSize(size)
89 {}
90 RColumnElementBase(const RColumnElementBase &elemArray, std::size_t at)
91 : fRawContent(static_cast<unsigned char *>(elemArray.fRawContent) + elemArray.fSize * at)
92 , fSize(elemArray.fSize)
93 {}
94 RColumnElementBase(const RColumnElementBase& other) = default;
98 virtual ~RColumnElementBase() = default;
99
100 static std::unique_ptr<RColumnElementBase> Generate(EColumnType type);
101 static std::size_t GetBitsOnStorage(EColumnType type);
102 static std::string GetTypeName(EColumnType type);
103
104 /// Write one or multiple column elements into destination
105 void WriteTo(void *destination, std::size_t count) const {
106 std::memcpy(destination, fRawContent, fSize * count);
107 }
108
109 /// Set the column element or an array of elements from the memory location source
110 void ReadFrom(void *source, std::size_t count) {
111 std::memcpy(fRawContent, source, fSize * count);
112 }
113
114 /// Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout
115 virtual bool IsMappable() const { R__ASSERT(false); return false; }
116 virtual std::size_t GetBitsOnStorage() const { R__ASSERT(false); return 0; }
117
118 /// If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-memory page
119 virtual void Pack(void *destination, void *source, std::size_t count) const
120 {
121 std::memcpy(destination, source, count);
122 }
123
124 /// If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-storage page
125 virtual void Unpack(void *destination, void *source, std::size_t count) const
126 {
127 std::memcpy(destination, source, count);
128 }
129
130 void *GetRawContent() const { return fRawContent; }
131 std::size_t GetSize() const { return fSize; }
132 std::size_t GetPackedSize(std::size_t nElements) const { return (nElements * GetBitsOnStorage() + 7) / 8; }
133};
134
135/**
136 * Base class for columns whose on-storage representation is little-endian.
137 * The implementation of `Pack` and `Unpack` takes care of byteswap if the memory page is big-endian.
138 */
139template <typename CppT>
141public:
142 static constexpr bool kIsMappable = (R__LITTLE_ENDIAN == 1);
143 RColumnElementLE(void *rawContent, std::size_t size) : RColumnElementBase(rawContent, size) {}
144
145 void Pack(void *dst, void *src, std::size_t count) const final
146 {
147#if R__LITTLE_ENDIAN == 1
148 RColumnElementBase::Pack(dst, src, count);
149#else
150 CopyElementsBswap<sizeof(CppT)>(dst, src, count);
151#endif
152 }
153 void Unpack(void *dst, void *src, std::size_t count) const final
154 {
155#if R__LITTLE_ENDIAN == 1
156 RColumnElementBase::Unpack(dst, src, count);
157#else
158 CopyElementsBswap<sizeof(CppT)>(dst, src, count);
159#endif
160 }
161};
162
163/**
164 * Pairs of C++ type and column type, like float and EColumnType::kReal32
165 */
166template <typename CppT, EColumnType ColumnT = EColumnType::kUnknown>
168public:
169 explicit RColumnElement(CppT* value) : RColumnElementBase(value, sizeof(CppT))
170 {
171 // Do not allow this template to be instantiated unless there is a specialization. The assert needs to depend
172 // on the template type or else the static_assert will always fire.
173 static_assert(sizeof(CppT) != sizeof(CppT), "No column mapping for this C++ type");
174 }
175};
176
177template <>
179public:
180 static constexpr std::size_t kSize = sizeof(bool);
182};
183
184template <>
186public:
187 static constexpr std::size_t kSize = sizeof(char);
189};
190
191template <>
192class RColumnElement<std::int8_t, EColumnType::kUnknown> : public RColumnElementBase {
193public:
194 static constexpr std::size_t kSize = sizeof(std::int8_t);
195 explicit RColumnElement(std::int8_t *value) : RColumnElementBase(value, kSize) {}
196};
197
198template <>
199class RColumnElement<std::uint8_t, EColumnType::kUnknown> : public RColumnElementBase {
200public:
201 static constexpr std::size_t kSize = sizeof(std::uint8_t);
202 explicit RColumnElement(std::uint8_t *value) : RColumnElementBase(value, kSize) {}
203};
204
205template <>
206class RColumnElement<std::int16_t, EColumnType::kUnknown> : public RColumnElementBase {
207public:
208 static constexpr std::size_t kSize = sizeof(std::int16_t);
209 explicit RColumnElement(std::int16_t *value) : RColumnElementBase(value, kSize) {}
210};
211
212template <>
213class RColumnElement<std::uint16_t, EColumnType::kUnknown> : public RColumnElementBase {
214public:
215 static constexpr std::size_t kSize = sizeof(std::uint16_t);
216 explicit RColumnElement(std::uint16_t *value) : RColumnElementBase(value, kSize) {}
217};
218
219template <>
220class RColumnElement<std::int32_t, EColumnType::kUnknown> : public RColumnElementBase {
221public:
222 static constexpr std::size_t kSize = sizeof(std::int32_t);
223 explicit RColumnElement(std::int32_t *value) : RColumnElementBase(value, kSize) {}
224};
225
226template <>
227class RColumnElement<std::uint32_t, EColumnType::kUnknown> : public RColumnElementBase {
228public:
229 static constexpr std::size_t kSize = sizeof(std::uint32_t);
230 explicit RColumnElement(std::uint32_t *value) : RColumnElementBase(value, kSize) {}
231};
232
233template <>
234class RColumnElement<std::int64_t, EColumnType::kUnknown> : public RColumnElementBase {
235public:
236 static constexpr std::size_t kSize = sizeof(std::int64_t);
237 explicit RColumnElement(std::int64_t *value) : RColumnElementBase(value, kSize) {}
238};
239
240template <>
241class RColumnElement<std::uint64_t, EColumnType::kUnknown> : public RColumnElementBase {
242public:
243 static constexpr std::size_t kSize = sizeof(std::uint64_t);
244 explicit RColumnElement(std::uint64_t *value) : RColumnElementBase(value, kSize) {}
245};
246
247template <>
249public:
250 static constexpr std::size_t kSize = sizeof(float);
252};
253
254template <>
256public:
257 static constexpr std::size_t kSize = sizeof(double);
259};
260
261template <>
263public:
264 static constexpr std::size_t kSize = sizeof(ClusterSize_t);
266};
267
268template <>
270public:
271 static constexpr std::size_t kSize = sizeof(RColumnSwitch);
273};
274
275template <>
276class RColumnElement<float, EColumnType::kReal32> : public RColumnElementLE<float> {
277public:
278 static constexpr std::size_t kSize = sizeof(float);
279 static constexpr std::size_t kBitsOnStorage = kSize * 8;
281 bool IsMappable() const final { return kIsMappable; }
282 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
283};
284
285template <>
287public:
288 static constexpr std::size_t kSize = sizeof(double);
289 static constexpr std::size_t kBitsOnStorage = kSize * 8;
291 bool IsMappable() const final { return kIsMappable; }
292 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
293};
294
295template <>
296class RColumnElement<std::int8_t, EColumnType::kInt8> : public RColumnElementBase {
297public:
298 static constexpr bool kIsMappable = true;
299 static constexpr std::size_t kSize = sizeof(std::int8_t);
300 static constexpr std::size_t kBitsOnStorage = kSize * 8;
301 explicit RColumnElement(std::int8_t *value) : RColumnElementBase(value, kSize) {}
302 bool IsMappable() const final { return kIsMappable; }
303 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
304};
305
306template <>
307class RColumnElement<std::uint8_t, EColumnType::kInt8> : public RColumnElementBase {
308public:
309 static constexpr bool kIsMappable = true;
310 static constexpr std::size_t kSize = sizeof(std::uint8_t);
311 static constexpr std::size_t kBitsOnStorage = kSize * 8;
312 explicit RColumnElement(std::uint8_t *value) : RColumnElementBase(value, kSize) {}
313 bool IsMappable() const final { return kIsMappable; }
314 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
315};
316
317template <>
318class RColumnElement<std::int8_t, EColumnType::kByte> : public RColumnElementBase {
319public:
320 static constexpr bool kIsMappable = true;
321 static constexpr std::size_t kSize = sizeof(std::int8_t);
322 static constexpr std::size_t kBitsOnStorage = kSize * 8;
323 explicit RColumnElement(std::int8_t *value) : RColumnElementBase(value, kSize) {}
324 bool IsMappable() const final { return kIsMappable; }
325 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
326};
327
328template <>
329class RColumnElement<std::uint8_t, EColumnType::kByte> : public RColumnElementBase {
330public:
331 static constexpr bool kIsMappable = true;
332 static constexpr std::size_t kSize = sizeof(std::uint8_t);
333 static constexpr std::size_t kBitsOnStorage = kSize * 8;
334 explicit RColumnElement(std::uint8_t *value) : RColumnElementBase(value, kSize) {}
335 bool IsMappable() const final { return kIsMappable; }
336 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
337};
338
339template <>
340class RColumnElement<std::int16_t, EColumnType::kInt16> : public RColumnElementLE<std::int16_t> {
341public:
342 static constexpr std::size_t kSize = sizeof(std::int16_t);
343 static constexpr std::size_t kBitsOnStorage = kSize * 8;
344 explicit RColumnElement(std::int16_t *value) : RColumnElementLE(value, kSize) {}
345 bool IsMappable() const final { return kIsMappable; }
346 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
347};
348
349template <>
350class RColumnElement<std::uint16_t, EColumnType::kInt16> : public RColumnElementLE<std::uint16_t> {
351public:
352 static constexpr std::size_t kSize = sizeof(std::uint16_t);
353 static constexpr std::size_t kBitsOnStorage = kSize * 8;
354 explicit RColumnElement(std::uint16_t *value) : RColumnElementLE(value, kSize) {}
355 bool IsMappable() const final { return kIsMappable; }
356 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
357};
358
359template <>
360class RColumnElement<std::int32_t, EColumnType::kInt32> : public RColumnElementLE<std::int32_t> {
361public:
362 static constexpr std::size_t kSize = sizeof(std::int32_t);
363 static constexpr std::size_t kBitsOnStorage = kSize * 8;
364 explicit RColumnElement(std::int32_t *value) : RColumnElementLE(value, kSize) {}
365 bool IsMappable() const final { return kIsMappable; }
366 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
367};
368
369template <>
370class RColumnElement<std::uint32_t, EColumnType::kInt32> : public RColumnElementLE<std::uint32_t> {
371public:
372 static constexpr std::size_t kSize = sizeof(std::uint32_t);
373 static constexpr std::size_t kBitsOnStorage = kSize * 8;
374 explicit RColumnElement(std::uint32_t *value) : RColumnElementLE(value, kSize) {}
375 bool IsMappable() const final { return kIsMappable; }
376 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
377};
378
379template <>
380class RColumnElement<std::int64_t, EColumnType::kInt64> : public RColumnElementLE<std::int64_t> {
381public:
382 static constexpr std::size_t kSize = sizeof(std::int64_t);
383 static constexpr std::size_t kBitsOnStorage = kSize * 8;
384 explicit RColumnElement(std::int64_t *value) : RColumnElementLE(value, kSize) {}
385 bool IsMappable() const final { return kIsMappable; }
386 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
387};
388
389template <>
390class RColumnElement<std::uint64_t, EColumnType::kInt64> : public RColumnElementLE<std::uint64_t> {
391public:
392 static constexpr std::size_t kSize = sizeof(std::uint64_t);
393 static constexpr std::size_t kBitsOnStorage = kSize * 8;
394 explicit RColumnElement(std::uint64_t *value) : RColumnElementLE(value, kSize) {}
395 bool IsMappable() const final { return kIsMappable; }
396 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
397};
398
399template <>
400class RColumnElement<ClusterSize_t, EColumnType::kIndex> : public RColumnElementLE<ClusterSize_t::ValueType> {
401public:
402 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::ClusterSize_t);
403 static constexpr std::size_t kBitsOnStorage = kSize * 8;
405 bool IsMappable() const final { return kIsMappable; }
406 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
407};
408
409template <>
411public:
412 static constexpr bool kIsMappable = false;
413 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::RColumnSwitch);
414 static constexpr std::size_t kBitsOnStorage = kSize * 8;
416 bool IsMappable() const final { return kIsMappable; }
417 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
418
419 void Pack(void *dst, void *src, std::size_t count) const final;
420 void Unpack(void *dst, void *src, std::size_t count) const final;
421};
422
423template <>
425public:
426 static constexpr bool kIsMappable = true;
427 static constexpr std::size_t kSize = sizeof(char);
428 static constexpr std::size_t kBitsOnStorage = kSize * 8;
430 bool IsMappable() const final { return kIsMappable; }
431 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
432};
433
434template <>
436public:
437 static constexpr bool kIsMappable = true;
438 static constexpr std::size_t kSize = sizeof(char);
439 static constexpr std::size_t kBitsOnStorage = kSize * 8;
441 bool IsMappable() const final { return kIsMappable; }
442 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
443};
444
445template <>
447public:
448 static constexpr bool kIsMappable = false;
449 static constexpr std::size_t kSize = sizeof(bool);
450 static constexpr std::size_t kBitsOnStorage = 1;
452 bool IsMappable() const final { return kIsMappable; }
453 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
454
455 void Pack(void *dst, void *src, std::size_t count) const final;
456 void Unpack(void *dst, void *src, std::size_t count) const final;
457};
458
459template <>
460class RColumnElement<std::int64_t, EColumnType::kInt32> : public RColumnElementBase {
461public:
462 static constexpr bool kIsMappable = false;
463 static constexpr std::size_t kSize = sizeof(std::int64_t);
464 static constexpr std::size_t kBitsOnStorage = 32;
465 explicit RColumnElement(std::int64_t *value) : RColumnElementBase(value, kSize) {}
466 bool IsMappable() const final { return kIsMappable; }
467 std::size_t GetBitsOnStorage() const final { return kBitsOnStorage; }
468
469 void Pack(void *dst, void *src, std::size_t count) const final;
470 void Unpack(void *dst, void *src, std::size_t count) const final;
471};
472
473} // namespace Detail
474} // namespace Experimental
475} // namespace ROOT
476
477#endif
#define R__LITTLE_ENDIAN
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Definition: TError.h:118
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 GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
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
@ kSize
Definition: TStructNode.h:26
@ kUnknown
Definition: TStructNode.h:19
virtual void Pack(void *destination, void *source, std::size_t count) const
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
static std::unique_ptr< RColumnElementBase > Generate(EColumnType type)
void WriteTo(void *destination, std::size_t count) const
Write one or multiple column elements into destination.
RColumnElementBase(RColumnElementBase &&other)=default
virtual bool IsMappable() const
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
void * fRawContent
Points to valid C++ data, either a single value or an array of values.
RColumnElementBase(void *rawContent, std::size_t size)
RColumnElementBase(const RColumnElementBase &other)=default
RColumnElementBase & operator=(const RColumnElementBase &other)=delete
std::size_t fSize
Size of the C++ value pointed to by fRawContent (not necessarily equal to the on-disk element size)
static std::string GetTypeName(EColumnType type)
void ReadFrom(void *source, std::size_t count)
Set the column element or an array of elements from the memory location source.
virtual void Unpack(void *destination, void *source, std::size_t count) const
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
RColumnElementBase(const RColumnElementBase &elemArray, std::size_t at)
std::size_t GetPackedSize(std::size_t nElements) const
Base class for columns whose on-storage representation is little-endian.
RColumnElementLE(void *rawContent, std::size_t size)
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
Pairs of C++ type and column type, like float and EColumnType::kReal32.
Holds the index and the tag of a kSwitch column.
Definition: RNTupleUtil.hxx:74
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:70
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Helper templated class for swapping bytes; specializations for N={2,4,8} are provided below.
Definition: Byteswap.h:124
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:58