Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RFieldFundamental.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/Fundamental.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-09
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, 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_RField_Fundamental
14#define ROOT_RField_Fundamental
15
16#ifndef ROOT_RField
17#error "Please include RField.hxx!"
18#endif
19
20#include <ROOT/RColumn.hxx>
21#include <ROOT/RFieldBase.hxx>
22#include <ROOT/RNTupleTypes.hxx>
23
24#include <cstddef>
25#include <memory>
26#include <string>
27#include <string_view>
28#include <type_traits>
29
30namespace ROOT {
31namespace Experimental {
32
33namespace Detail {
34class RFieldVisitor;
35} // namespace Detail
36
37} // namespace Experimental
38
39////////////////////////////////////////////////////////////////////////////////
40/// Template specializations for concrete C++ fundamental types
41////////////////////////////////////////////////////////////////////////////////
42
43template <>
44class RField<void> : public RFieldBase {
45public:
46 static std::string TypeName() { return "void"; }
47 // RField<void> should never be constructed.
48 RField() = delete;
49 RField(const RField &) = delete;
50 RField &operator=(const RField &) = delete;
51};
52
53////////////////////////////////////////////////////////////////////////////////
54/// Template specializations for integral types
55////////////////////////////////////////////////////////////////////////////////
56
57// bool and char are somewhat special, handle them first
58
59extern template class RSimpleField<bool>;
60
61template <>
62class RField<bool> final : public RSimpleField<bool> {
63protected:
64 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
65 {
66 return std::make_unique<RField>(newName);
67 }
68
69 const RColumnRepresentations &GetColumnRepresentations() const final;
70
71public:
72 static std::string TypeName() { return "bool"; }
73 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
74 RField(RField &&other) = default;
75 RField &operator=(RField &&other) = default;
76 ~RField() final = default;
77
78 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
79};
80
81extern template class RSimpleField<char>;
82
83template <>
84class RField<char> final : public RSimpleField<char> {
85protected:
86 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
87 {
88 return std::make_unique<RField>(newName);
89 }
90
91 const RColumnRepresentations &GetColumnRepresentations() const final;
92
93public:
94 static std::string TypeName() { return "char"; }
95 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
96 RField(RField &&other) = default;
97 RField &operator=(RField &&other) = default;
98 ~RField() final = default;
99
100 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
101};
102
103// For other integral types, we introduce an intermediate RIntegralField. It is specialized for fixed-width integer
104// types (from std::[u]int8_t to std::[u]int64_t). RField<T> for integral types T is specialized by mapping to the
105// corresponding fixed-width integer type (see RIntegralTypeMap).
106
107template <typename T>
109 // Instantiating this base template definition should never happen and is an error!
110 RIntegralField() = delete;
111};
112
113extern template class RSimpleField<std::int8_t>;
114
115template <>
117protected:
118 const RColumnRepresentations &GetColumnRepresentations() const final;
119
120public:
121 static std::string TypeName() { return "std::int8_t"; }
122 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
123 RIntegralField(RIntegralField &&other) = default;
124 RIntegralField &operator=(RIntegralField &&other) = default;
125 ~RIntegralField() override = default;
126
127 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
128};
129
130extern template class RSimpleField<std::uint8_t>;
131
132template <>
134protected:
135 const RColumnRepresentations &GetColumnRepresentations() const final;
136
137public:
138 static std::string TypeName() { return "std::uint8_t"; }
139 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
140 RIntegralField(RIntegralField &&other) = default;
141 RIntegralField &operator=(RIntegralField &&other) = default;
142 ~RIntegralField() override = default;
143
144 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
145};
146
147extern template class RSimpleField<std::int16_t>;
148
149template <>
151protected:
152 const RColumnRepresentations &GetColumnRepresentations() const final;
153
154public:
155 static std::string TypeName() { return "std::int16_t"; }
156 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
157 RIntegralField(RIntegralField &&other) = default;
158 RIntegralField &operator=(RIntegralField &&other) = default;
159 ~RIntegralField() override = default;
160
161 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
162};
163
164extern template class RSimpleField<std::uint16_t>;
165
166template <>
168protected:
169 const RColumnRepresentations &GetColumnRepresentations() const final;
170
171public:
172 static std::string TypeName() { return "std::uint16_t"; }
173 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
174 RIntegralField(RIntegralField &&other) = default;
175 RIntegralField &operator=(RIntegralField &&other) = default;
176 ~RIntegralField() override = default;
177
178 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
179};
180
181extern template class RSimpleField<std::int32_t>;
182
183template <>
185protected:
186 const RColumnRepresentations &GetColumnRepresentations() const final;
187
188public:
189 static std::string TypeName() { return "std::int32_t"; }
190 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
191 RIntegralField(RIntegralField &&other) = default;
192 RIntegralField &operator=(RIntegralField &&other) = default;
193 ~RIntegralField() override = default;
194
195 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
196};
197
198extern template class RSimpleField<std::uint32_t>;
199
200template <>
202protected:
203 const RColumnRepresentations &GetColumnRepresentations() const final;
204
205public:
206 static std::string TypeName() { return "std::uint32_t"; }
207 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
208 RIntegralField(RIntegralField &&other) = default;
209 RIntegralField &operator=(RIntegralField &&other) = default;
210 ~RIntegralField() override = default;
211
212 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
213};
214
215extern template class RSimpleField<std::int64_t>;
216
217template <>
219protected:
220 const RColumnRepresentations &GetColumnRepresentations() const final;
221
222public:
223 static std::string TypeName() { return "std::int64_t"; }
224 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
225 RIntegralField(RIntegralField &&other) = default;
226 RIntegralField &operator=(RIntegralField &&other) = default;
227 ~RIntegralField() override = default;
228
229 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
230};
231
232extern template class RSimpleField<std::uint64_t>;
233
234template <>
236protected:
237 const RColumnRepresentations &GetColumnRepresentations() const final;
238
239public:
240 static std::string TypeName() { return "std::uint64_t"; }
241 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
242 RIntegralField(RIntegralField &&other) = default;
243 RIntegralField &operator=(RIntegralField &&other) = default;
244 ~RIntegralField() override = default;
245
246 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
247};
248
249namespace Internal {
250// Map standard integer types to fixed width equivalents.
251template <typename T>
253 using type = T;
254};
255
256// RField<char> has its own specialization, we should not need a specialization of RIntegralTypeMap.
257// From https://en.cppreference.com/w/cpp/language/types:
258// char has the same representation and alignment as either signed char or
259// unsigned char, but is always a distinct type.
260template <>
262 static_assert(sizeof(signed char) == sizeof(std::int8_t));
263 using type = std::int8_t;
264};
265template <>
267 static_assert(sizeof(unsigned char) == sizeof(std::uint8_t));
268 using type = std::uint8_t;
269};
270template <>
272 static_assert(sizeof(short) == sizeof(std::int16_t));
273 using type = std::int16_t;
274};
275template <>
277 static_assert(sizeof(unsigned short) == sizeof(std::uint16_t));
278 using type = std::uint16_t;
279};
280template <>
282 static_assert(sizeof(int) == sizeof(std::int32_t));
283 using type = std::int32_t;
284};
285template <>
287 static_assert(sizeof(unsigned int) == sizeof(std::uint32_t));
288 using type = std::uint32_t;
289};
290template <>
292 static_assert(sizeof(long) == sizeof(std::int32_t) || sizeof(long) == sizeof(std::int64_t));
293 using type = std::conditional_t<sizeof(long) == sizeof(std::int32_t), std::int32_t, std::int64_t>;
294};
295template <>
296struct RIntegralTypeMap<unsigned long> {
297 static_assert(sizeof(unsigned long) == sizeof(std::uint32_t) || sizeof(unsigned long) == sizeof(std::uint64_t));
298 using type = std::conditional_t<sizeof(unsigned long) == sizeof(std::uint32_t), std::uint32_t, std::uint64_t>;
299};
300template <>
301struct RIntegralTypeMap<long long> {
302 static_assert(sizeof(long long) == sizeof(std::int64_t));
303 using type = std::int64_t;
304};
305template <>
306struct RIntegralTypeMap<unsigned long long> {
307 static_assert(sizeof(unsigned long long) == sizeof(std::uint64_t));
308 using type = std::uint64_t;
309};
310} // namespace Internal
311
312template <typename T>
313class RField<T, typename std::enable_if<std::is_integral_v<T>>::type> final
314 : public RIntegralField<typename Internal::RIntegralTypeMap<T>::type> {
315 using MappedType = typename Internal::RIntegralTypeMap<T>::type;
316 static_assert(sizeof(T) == sizeof(MappedType), "invalid size of mapped type");
317 static_assert(std::is_signed_v<T> == std::is_signed_v<MappedType>, "invalid signedness of mapped type");
318 using BaseType = RIntegralField<MappedType>;
319
320protected:
321 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
322 {
323 return std::make_unique<RField>(newName);
324 }
325
326public:
327 RField(std::string_view name) : RIntegralField<MappedType>(name) {}
328 RField(RField &&other) = default;
329 RField &operator=(RField &&other) = default;
330 ~RField() final = default;
331
332 T *Map(ROOT::NTupleSize_t globalIndex) { return reinterpret_cast<T *>(this->BaseType::Map(globalIndex)); }
333 T *Map(RNTupleLocalIndex localIndex) { return reinterpret_cast<T *>(this->BaseType::Map(localIndex)); }
334 T *MapV(ROOT::NTupleSize_t globalIndex, ROOT::NTupleSize_t &nItems)
335 {
336 return reinterpret_cast<T *>(this->BaseType::MapV(globalIndex, nItems));
337 }
338 T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
339 {
340 return reinterpret_cast<T *>(this->BaseType::MapV(localIndex, nItems));
341 }
342};
343
344////////////////////////////////////////////////////////////////////////////////
345/// Template specializations for floating-point types
346////////////////////////////////////////////////////////////////////////////////
347
348extern template class RSimpleField<double>;
349extern template class RSimpleField<float>;
350
351template <typename T>
354
358
359 std::size_t fBitWidth = sizeof(T) * 8;
360 double fValueMin = std::numeric_limits<T>::min();
361 double fValueMax = std::numeric_limits<T>::max();
362
363protected:
364 /// Called by derived fields' CloneImpl()
365 RRealField(std::string_view name, const RRealField &source)
366 : RSimpleField<T>(name, source.GetTypeName()),
367 fBitWidth(source.fBitWidth),
368 fValueMin(source.fValueMin),
369 fValueMax(source.fValueMax)
370 {
371 }
372
373 void GenerateColumns() final
374 {
375 const auto r = Base::GetColumnRepresentatives();
376 const auto n = r.size();
377 fAvailableColumns.reserve(n);
378 for (std::uint16_t i = 0; i < n; ++i) {
379 auto &column = fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(r[i][0], 0, i));
381 column->SetBitsOnStorage(fBitWidth);
382 } else if (r[i][0] == ROOT::ENTupleColumnType::kReal32Quant) {
383 column->SetBitsOnStorage(fBitWidth);
384 column->SetValueRange(fValueMin, fValueMax);
385 }
386 }
388 }
389
391 {
392 std::uint16_t representationIndex = 0;
393 do {
394 const auto &onDiskTypes = Base::EnsureCompatibleColumnTypes(desc, representationIndex);
395 if (onDiskTypes.empty())
396 break;
397
398 auto &column =
399 fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(onDiskTypes[0], 0, representationIndex));
400 if (onDiskTypes[0] == ROOT::ENTupleColumnType::kReal32Trunc) {
401 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
402 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
403 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
404 } else if (onDiskTypes[0] == ROOT::ENTupleColumnType::kReal32Quant) {
405 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
406 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
407 assert(coldesc.GetValueRange().has_value());
408 const auto [valMin, valMax] = *coldesc.GetValueRange();
409 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
410 column->SetValueRange(valMin, valMax);
411 }
412 fColumnRepresentatives.emplace_back(onDiskTypes);
413 if (representationIndex > 0) {
414 fAvailableColumns[0]->MergeTeams(*fAvailableColumns[representationIndex]);
415 }
416
417 representationIndex++;
418 } while (true);
420 }
421
422 ~RRealField() override = default;
423
424public:
426
427 RRealField(std::string_view name, std::string_view typeName) : RSimpleField<T>(name, typeName) {}
428 RRealField(RRealField &&other) = default;
429 RRealField &operator=(RRealField &&other) = default;
430
431 /// Sets this field to use a half precision representation, occupying half as much storage space (16 bits:
432 /// 1 sign bit, 5 exponent bits, 10 mantissa bits) on disk.
433 /// This is mutually exclusive with SetTruncated() and SetQuantized() and supersedes them if called after them.
435
436 /// Set the on-disk representation of this field to a single-precision float truncated to `nBits`.
437 /// The remaining (32 - `nBits`) bits will be truncated from the number's mantissa.
438 /// `nBits` must be $10 <= nBits <= 31$ (this means that at least 1 bit
439 /// of mantissa is always preserved). Note that this effectively rounds the number towards 0.
440 /// For a double-precision field, this implies first a cast to single-precision, then the truncation.
441 /// This is mutually exclusive with SetHalfPrecision() and SetQuantized() and supersedes them if called after them.
442 void SetTruncated(std::size_t nBits)
443 {
444 const auto &[minBits, maxBits] =
446 if (nBits < minBits || nBits > maxBits) {
447 throw RException(R__FAIL("SetTruncated() argument nBits = " + std::to_string(nBits) +
448 " is out of valid range [" + std::to_string(minBits) + ", " +
449 std::to_string(maxBits) + "])"));
450 }
452 fBitWidth = nBits;
453 }
454
455 /// Sets this field to use a quantized integer representation using `nBits` per value.
456 /// It must be $1 <= nBits <= 32$.
457 /// `valueRange.first` and `valueRange.second` are respectively the min and max value allowed for this field.
458 /// They must not be infinity, `NaN` or denormal floats, and valueRange.second must be greater or equal to
459 /// valueRange.first.
460 /// Calling this function establishes a promise by the caller to RNTuple that this field will only
461 /// contain values contained in `[minValue, maxValue]` inclusive. If a value outside this range is assigned to this
462 /// field, the behavior is undefined. This is mutually exclusive with SetTruncated() and SetHalfPrecision() and
463 /// supersedes them if called after them.
464 void SetQuantized(std::size_t nBits, std::pair<T, T> valueRange)
465 {
466 const auto &[minBits, maxBits] =
468 if (valueRange.second < valueRange.first) {
469 throw RException(R__FAIL("value range given to SetQuantized() has max < min! (" +
470 std::to_string(valueRange.second) + " < " + std::to_string(valueRange.first) + ")"));
471 }
472 if (nBits < minBits || nBits > maxBits) {
473 throw RException(R__FAIL("SetQuantized() argument nBits = " + std::to_string(nBits) +
474 " is out of valid range [" + std::to_string(minBits) + ", " +
475 std::to_string(maxBits) + "])"));
476 }
478 fBitWidth = nBits;
479 fValueMin = valueRange.first;
480 fValueMax = valueRange.second;
481 }
482};
483
484template <>
485class RField<float> final : public RRealField<float> {
487
488 RField(std::string_view name, const RField &source) : RRealField<float>(name, source) {}
489
490 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
491 {
492 return std::unique_ptr<RField>(new RField(newName, *this));
493 }
494
495public:
496 static std::string TypeName() { return "float"; }
497
498 explicit RField(std::string_view name) : RRealField<float>(name, TypeName()) {}
499
500 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
501};
502
503template <>
504class RField<double> final : public RRealField<double> {
506
507 RField(std::string_view name, const RField &source) : RRealField<double>(name, source) {}
508
509 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
510 {
511 return std::unique_ptr<RField>(new RField(newName, *this));
512 }
513
514public:
515 static std::string TypeName() { return "double"; }
516
517 explicit RField(std::string_view name) : RRealField<double>(name, TypeName()) {}
518
519 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
520
521 // Set the column representation to 32 bit floating point and the type alias to `Double32_t`
522 void SetDouble32();
523};
524
525} // namespace ROOT
526
527#endif
ROOT::R::TRInterface & r
Definition Object.C:4
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
char name[80]
Definition TGX11.cxx:148
Binding & operator=(OUT(*fun)(void))
Abstract base class for classes implementing the visitor design pattern.
static std::pair< std::uint16_t, std::uint16_t > GetValidBitRange(ROOT::ENTupleColumnType type)
Most types have a fixed on-disk bit width.
static std::unique_ptr< RColumn > Create(ROOT::ENTupleColumnType type, std::uint32_t columnIdx, std::uint16_t representationIdx)
Definition RColumn.hxx:106
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
The list of column representations a field can have.
void SetColumnRepresentatives(const RColumnRepresentations::Selection_t &representatives)
Fixes a column representative.
ROOT::Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const ROOT::RNTupleDescriptor &desc, std::uint16_t representationIndex) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId and the given represe...
std::vector< std::reference_wrapper< const ColumnRepresentation_t > > fColumnRepresentatives
Pointers into the static vector returned by RColumnRepresentations::GetSerializationTypes() when SetC...
std::vector< std::unique_ptr< ROOT::Internal::RColumn > > fAvailableColumns
The columns are connected either to a sink or to a source (not to both); they are owned by the field.
RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
RColumnRepresentations::Selection_t GetColumnRepresentatives() const
Returns the fColumnRepresentative pointee or, if unset (always the case for artificial fields),...
const std::string & GetTypeName() const
ROOT::DescriptorId_t GetOnDiskId() const
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:293
~RField() final=default
static std::string TypeName()
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
RField(std::string_view name)
RField & operator=(RField &&other)=default
RField(RField &&other)=default
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
RField(RField &&other)=default
RField & operator=(RField &&other)=default
~RField() final=default
RField(std::string_view name)
static std::string TypeName()
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:191
RField(std::string_view name, const RField &source)
RField(std::string_view name)
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:322
static std::string TypeName()
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static std::string TypeName()
RField(std::string_view name)
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:302
RField(std::string_view name, const RField &source)
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static std::string TypeName()
RField & operator=(const RField &)=delete
RField(const RField &)=delete
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:320
~RField() final=default
RField & operator=(RField &&other)=default
RField(std::string_view name)
Definition RField.hxx:323
The on-storage metadata of an RNTuple.
~RRealField() override=default
RRealField(std::string_view name, const RRealField &source)
Called by derived fields' CloneImpl().
RRealField(std::string_view name, std::string_view typeName)
void SetHalfPrecision()
Sets this field to use a half precision representation, occupying half as much storage space (16 bits...
RSimpleField< T > Base
void SetQuantized(std::size_t nBits, std::pair< T, T > valueRange)
Sets this field to use a quantized integer representation using nBits per value.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
void SetTruncated(std::size_t nBits)
Set the on-disk representation of this field to a single-precision float truncated to nBits.
RRealField & operator=(RRealField &&other)=default
void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final
Implementations in derived classes should create the backing columns corresponding to the field type ...
RRealField(RRealField &&other)=default
RSimpleField(std::string_view name, std::string_view type)
Definition RField.hxx:406
auto Map(Args &&... args)
Create new collection applying a callable to the elements of the input collection.
Definition RVec.hxx:2146
const Int_t n
Definition legend1.C:16
Special implementation of ROOT::RRangeCast for TCollection, including a check that the cast target ty...
Definition TObject.h:395
Namespace for ROOT features in testing.
Definition TROOT.h:100
double T(double x)
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
std::conditional_t< sizeof(long)==sizeof(std::int32_t), std::int32_t, std::int64_t > type
std::conditional_t< sizeof(unsigned long)==sizeof(std::uint32_t), std::uint32_t, std::uint64_t > type