1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#ifndef ARROW_TYPE_TRAITS_H
19#define ARROW_TYPE_TRAITS_H
20
21#include <memory>
22#include <type_traits>
23
24#include "arrow/type_fwd.h"
25#include "arrow/util/bit-util.h"
26
27namespace arrow {
28
29//
30// Per-type type traits
31//
32
33template <typename T>
34struct TypeTraits {};
35
36template <>
37struct TypeTraits<NullType> {
38 using ArrayType = NullArray;
39 using BuilderType = NullBuilder;
40 constexpr static bool is_parameter_free = false;
41};
42
43template <>
44struct TypeTraits<UInt8Type> {
45 using ArrayType = UInt8Array;
46 using BuilderType = UInt8Builder;
47 using TensorType = UInt8Tensor;
48 static constexpr int64_t bytes_required(int64_t elements) { return elements; }
49 constexpr static bool is_parameter_free = true;
50 static inline std::shared_ptr<DataType> type_singleton() { return uint8(); }
51};
52
53template <>
54struct TypeTraits<Int8Type> {
55 using ArrayType = Int8Array;
56 using BuilderType = Int8Builder;
57 using TensorType = Int8Tensor;
58 static constexpr int64_t bytes_required(int64_t elements) { return elements; }
59 constexpr static bool is_parameter_free = true;
60 static inline std::shared_ptr<DataType> type_singleton() { return int8(); }
61};
62
63template <>
64struct TypeTraits<UInt16Type> {
65 using ArrayType = UInt16Array;
66 using BuilderType = UInt16Builder;
67 using TensorType = UInt16Tensor;
68
69 static constexpr int64_t bytes_required(int64_t elements) {
70 return elements * sizeof(uint16_t);
71 }
72 constexpr static bool is_parameter_free = true;
73 static inline std::shared_ptr<DataType> type_singleton() { return uint16(); }
74};
75
76template <>
77struct TypeTraits<Int16Type> {
78 using ArrayType = Int16Array;
79 using BuilderType = Int16Builder;
80 using TensorType = Int16Tensor;
81
82 static constexpr int64_t bytes_required(int64_t elements) {
83 return elements * sizeof(int16_t);
84 }
85 constexpr static bool is_parameter_free = true;
86 static inline std::shared_ptr<DataType> type_singleton() { return int16(); }
87};
88
89template <>
90struct TypeTraits<UInt32Type> {
91 using ArrayType = UInt32Array;
92 using BuilderType = UInt32Builder;
93 using TensorType = UInt32Tensor;
94
95 static constexpr int64_t bytes_required(int64_t elements) {
96 return elements * sizeof(uint32_t);
97 }
98 constexpr static bool is_parameter_free = true;
99 static inline std::shared_ptr<DataType> type_singleton() { return uint32(); }
100};
101
102template <>
103struct TypeTraits<Int32Type> {
104 using ArrayType = Int32Array;
105 using BuilderType = Int32Builder;
106 using TensorType = Int32Tensor;
107
108 static constexpr int64_t bytes_required(int64_t elements) {
109 return elements * sizeof(int32_t);
110 }
111 constexpr static bool is_parameter_free = true;
112 static inline std::shared_ptr<DataType> type_singleton() { return int32(); }
113};
114
115template <>
116struct TypeTraits<UInt64Type> {
117 using ArrayType = UInt64Array;
118 using BuilderType = UInt64Builder;
119 using TensorType = UInt64Tensor;
120
121 static constexpr int64_t bytes_required(int64_t elements) {
122 return elements * sizeof(uint64_t);
123 }
124 constexpr static bool is_parameter_free = true;
125 static inline std::shared_ptr<DataType> type_singleton() { return uint64(); }
126};
127
128template <>
129struct TypeTraits<Int64Type> {
130 using ArrayType = Int64Array;
131 using BuilderType = Int64Builder;
132 using TensorType = Int64Tensor;
133
134 static constexpr int64_t bytes_required(int64_t elements) {
135 return elements * sizeof(int64_t);
136 }
137 constexpr static bool is_parameter_free = true;
138 static inline std::shared_ptr<DataType> type_singleton() { return int64(); }
139};
140
141template <>
142struct TypeTraits<Date64Type> {
143 using ArrayType = Date64Array;
144 using BuilderType = Date64Builder;
145
146 static constexpr int64_t bytes_required(int64_t elements) {
147 return elements * sizeof(int64_t);
148 }
149 constexpr static bool is_parameter_free = true;
150 static inline std::shared_ptr<DataType> type_singleton() { return date64(); }
151};
152
153template <>
154struct TypeTraits<Date32Type> {
155 using ArrayType = Date32Array;
156 using BuilderType = Date32Builder;
157
158 static constexpr int64_t bytes_required(int64_t elements) {
159 return elements * sizeof(int32_t);
160 }
161 constexpr static bool is_parameter_free = true;
162 static inline std::shared_ptr<DataType> type_singleton() { return date32(); }
163};
164
165template <>
166struct TypeTraits<TimestampType> {
167 using ArrayType = TimestampArray;
168 using BuilderType = TimestampBuilder;
169
170 static constexpr int64_t bytes_required(int64_t elements) {
171 return elements * sizeof(int64_t);
172 }
173 constexpr static bool is_parameter_free = false;
174};
175
176template <>
177struct TypeTraits<Time32Type> {
178 using ArrayType = Time32Array;
179 using BuilderType = Time32Builder;
180
181 static constexpr int64_t bytes_required(int64_t elements) {
182 return elements * sizeof(int32_t);
183 }
184 constexpr static bool is_parameter_free = false;
185};
186
187template <>
188struct TypeTraits<Time64Type> {
189 using ArrayType = Time64Array;
190 using BuilderType = Time64Builder;
191
192 static constexpr int64_t bytes_required(int64_t elements) {
193 return elements * sizeof(int64_t);
194 }
195 constexpr static bool is_parameter_free = false;
196};
197
198template <>
199struct TypeTraits<HalfFloatType> {
200 using ArrayType = HalfFloatArray;
201 using BuilderType = HalfFloatBuilder;
202 using TensorType = HalfFloatTensor;
203
204 static constexpr int64_t bytes_required(int64_t elements) {
205 return elements * sizeof(uint16_t);
206 }
207 constexpr static bool is_parameter_free = true;
208 static inline std::shared_ptr<DataType> type_singleton() { return float16(); }
209};
210
211template <>
212struct TypeTraits<FloatType> {
213 using ArrayType = FloatArray;
214 using BuilderType = FloatBuilder;
215 using TensorType = FloatTensor;
216
217 static constexpr int64_t bytes_required(int64_t elements) {
218 return static_cast<int64_t>(elements * sizeof(float));
219 }
220 constexpr static bool is_parameter_free = true;
221 static inline std::shared_ptr<DataType> type_singleton() { return float32(); }
222};
223
224template <>
225struct TypeTraits<DoubleType> {
226 using ArrayType = DoubleArray;
227 using BuilderType = DoubleBuilder;
228 using TensorType = DoubleTensor;
229
230 static constexpr int64_t bytes_required(int64_t elements) {
231 return static_cast<int64_t>(elements * sizeof(double));
232 }
233 constexpr static bool is_parameter_free = true;
234 static inline std::shared_ptr<DataType> type_singleton() { return float64(); }
235};
236
237template <>
238struct TypeTraits<Decimal128Type> {
239 using ArrayType = Decimal128Array;
240 using BuilderType = Decimal128Builder;
241 constexpr static bool is_parameter_free = false;
242};
243
244template <>
245struct TypeTraits<BooleanType> {
246 using ArrayType = BooleanArray;
247 using BuilderType = BooleanBuilder;
248
249 static constexpr int64_t bytes_required(int64_t elements) {
250 return BitUtil::BytesForBits(elements);
251 }
252 constexpr static bool is_parameter_free = true;
253 static inline std::shared_ptr<DataType> type_singleton() { return boolean(); }
254};
255
256template <>
257struct TypeTraits<StringType> {
258 using ArrayType = StringArray;
259 using BuilderType = StringBuilder;
260 constexpr static bool is_parameter_free = true;
261 static inline std::shared_ptr<DataType> type_singleton() { return utf8(); }
262};
263
264template <>
265struct TypeTraits<BinaryType> {
266 using ArrayType = BinaryArray;
267 using BuilderType = BinaryBuilder;
268 constexpr static bool is_parameter_free = true;
269 static inline std::shared_ptr<DataType> type_singleton() { return binary(); }
270};
271
272template <>
273struct TypeTraits<FixedSizeBinaryType> {
274 using ArrayType = FixedSizeBinaryArray;
275 using BuilderType = FixedSizeBinaryBuilder;
276 constexpr static bool is_parameter_free = false;
277};
278
279template <>
280struct TypeTraits<ListType> {
281 using ArrayType = ListArray;
282 using BuilderType = ListBuilder;
283 constexpr static bool is_parameter_free = false;
284};
285
286template <>
287struct TypeTraits<StructType> {
288 using ArrayType = StructArray;
289 using BuilderType = StructBuilder;
290 constexpr static bool is_parameter_free = false;
291};
292
293template <>
294struct TypeTraits<UnionType> {
295 using ArrayType = UnionArray;
296 constexpr static bool is_parameter_free = false;
297};
298
299template <>
300struct TypeTraits<DictionaryType> {
301 using ArrayType = DictionaryArray;
302 constexpr static bool is_parameter_free = false;
303};
304
305//
306// Useful type predicates
307//
308
309template <typename T>
310using is_number = std::is_base_of<Number, T>;
311
312template <typename T>
313struct has_c_type {
314 static constexpr bool value =
315 (std::is_base_of<PrimitiveCType, T>::value || std::is_base_of<DateType, T>::value ||
316 std::is_base_of<TimeType, T>::value || std::is_base_of<TimestampType, T>::value);
317};
318
319template <typename T>
320struct is_8bit_int {
321 static constexpr bool value =
322 (std::is_same<UInt8Type, T>::value || std::is_same<Int8Type, T>::value);
323};
324
325template <typename T>
326using enable_if_8bit_int = typename std::enable_if<is_8bit_int<T>::value>::type;
327
328template <typename T>
329using enable_if_primitive_ctype =
330 typename std::enable_if<std::is_base_of<PrimitiveCType, T>::value>::type;
331
332template <typename T>
333using enable_if_date = typename std::enable_if<std::is_base_of<DateType, T>::value>::type;
334
335template <typename T>
336using enable_if_integer =
337 typename std::enable_if<std::is_base_of<Integer, T>::value>::type;
338
339template <typename T>
340using enable_if_signed_integer =
341 typename std::enable_if<std::is_base_of<Integer, T>::value &&
342 std::is_signed<typename T::c_type>::value>::type;
343
344template <typename T>
345using enable_if_unsigned_integer =
346 typename std::enable_if<std::is_base_of<Integer, T>::value &&
347 std::is_unsigned<typename T::c_type>::value>::type;
348
349template <typename T>
350using enable_if_floating_point =
351 typename std::enable_if<std::is_base_of<FloatingPoint, T>::value>::type;
352
353template <typename T>
354using enable_if_time = typename std::enable_if<std::is_base_of<TimeType, T>::value>::type;
355
356template <typename T>
357using enable_if_timestamp =
358 typename std::enable_if<std::is_base_of<TimestampType, T>::value>::type;
359
360template <typename T>
361using enable_if_has_c_type = typename std::enable_if<has_c_type<T>::value>::type;
362
363template <typename T>
364using enable_if_null = typename std::enable_if<std::is_same<NullType, T>::value>::type;
365
366template <typename T>
367using enable_if_binary =
368 typename std::enable_if<std::is_base_of<BinaryType, T>::value>::type;
369
370template <typename T>
371using enable_if_boolean =
372 typename std::enable_if<std::is_same<BooleanType, T>::value>::type;
373
374template <typename T>
375using enable_if_binary_like =
376 typename std::enable_if<std::is_base_of<BinaryType, T>::value ||
377 std::is_base_of<FixedSizeBinaryType, T>::value>::type;
378
379template <typename T>
380using enable_if_fixed_size_binary =
381 typename std::enable_if<std::is_base_of<FixedSizeBinaryType, T>::value>::type;
382
383template <typename T>
384using enable_if_list = typename std::enable_if<std::is_base_of<ListType, T>::value>::type;
385
386template <typename T>
387using enable_if_number = typename std::enable_if<is_number<T>::value>::type;
388
389namespace detail {
390
391// Not all type classes have a c_type
392template <typename T>
393struct as_void {
394 using type = void;
395};
396
397// The partial specialization will match if T has the ATTR_NAME member
398#define GET_ATTR(ATTR_NAME, DEFAULT) \
399 template <typename T, typename Enable = void> \
400 struct GetAttr_##ATTR_NAME { \
401 using type = DEFAULT; \
402 }; \
403 \
404 template <typename T> \
405 struct GetAttr_##ATTR_NAME<T, typename as_void<typename T::ATTR_NAME>::type> { \
406 using type = typename T::ATTR_NAME; \
407 };
408
409GET_ATTR(c_type, void)
410GET_ATTR(TypeClass, void)
411
412#undef GET_ATTR
413
414} // namespace detail
415
416#define PRIMITIVE_TRAITS(T) \
417 using TypeClass = \
418 typename std::conditional<std::is_base_of<DataType, T>::value, T, \
419 typename detail::GetAttr_TypeClass<T>::type>::type; \
420 using c_type = typename detail::GetAttr_c_type<TypeClass>::type
421
422template <typename T>
423struct IsUnsignedInt {
424 PRIMITIVE_TRAITS(T);
425 static constexpr bool value =
426 std::is_integral<c_type>::value && std::is_unsigned<c_type>::value;
427};
428
429template <typename T>
430struct IsSignedInt {
431 PRIMITIVE_TRAITS(T);
432 static constexpr bool value =
433 std::is_integral<c_type>::value && std::is_signed<c_type>::value;
434};
435
436template <typename T>
437struct IsInteger {
438 PRIMITIVE_TRAITS(T);
439 static constexpr bool value = std::is_integral<c_type>::value;
440};
441
442template <typename T>
443struct IsFloatingPoint {
444 PRIMITIVE_TRAITS(T);
445 static constexpr bool value = std::is_floating_point<c_type>::value;
446};
447
448template <typename T>
449struct IsNumeric {
450 PRIMITIVE_TRAITS(T);
451 static constexpr bool value = std::is_arithmetic<c_type>::value;
452};
453
454static inline bool is_integer(Type::type type_id) {
455 switch (type_id) {
456 case Type::UINT8:
457 case Type::INT8:
458 case Type::UINT16:
459 case Type::INT16:
460 case Type::UINT32:
461 case Type::INT32:
462 case Type::UINT64:
463 case Type::INT64:
464 return true;
465 default:
466 break;
467 }
468 return false;
469}
470
471static inline bool is_floating(Type::type type_id) {
472 switch (type_id) {
473 case Type::HALF_FLOAT:
474 case Type::FLOAT:
475 case Type::DOUBLE:
476 return true;
477 default:
478 break;
479 }
480 return false;
481}
482
483static inline bool is_primitive(Type::type type_id) {
484 switch (type_id) {
485 case Type::NA:
486 case Type::BOOL:
487 case Type::UINT8:
488 case Type::INT8:
489 case Type::UINT16:
490 case Type::INT16:
491 case Type::UINT32:
492 case Type::INT32:
493 case Type::UINT64:
494 case Type::INT64:
495 case Type::HALF_FLOAT:
496 case Type::FLOAT:
497 case Type::DOUBLE:
498 case Type::DATE32:
499 case Type::DATE64:
500 case Type::TIME32:
501 case Type::TIME64:
502 case Type::TIMESTAMP:
503 case Type::INTERVAL:
504 return true;
505 default:
506 break;
507 }
508 return false;
509}
510
511static inline bool is_binary_like(Type::type type_id) {
512 switch (type_id) {
513 case Type::BINARY:
514 case Type::STRING:
515 return true;
516 default:
517 break;
518 }
519 return false;
520}
521
522static inline bool is_dictionary(Type::type type_id) {
523 return type_id == Type::DICTIONARY;
524}
525
526} // namespace arrow
527
528#endif // ARROW_TYPE_TRAITS_H
529