1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/common/radix.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/common.hpp"
12#include "duckdb/common/exception.hpp"
13#include "duckdb/common/types.hpp"
14#include "duckdb/common/types/string_type.hpp"
15#include "duckdb/common/types/value.hpp"
16
17#include <cfloat>
18#include <cstring> // strlen() on Solaris
19#include <limits.h>
20
21namespace duckdb {
22
23#define BSWAP16(x) ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | (((uint16_t)(x)&0x00ff) << 8)))
24
25#define BSWAP32(x) \
26 ((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | (((uint32_t)(x)&0x00ff0000) >> 8) | \
27 (((uint32_t)(x)&0x0000ff00) << 8) | (((uint32_t)(x)&0x000000ff) << 24)))
28
29#define BSWAP64(x) \
30 ((uint64_t)((((uint64_t)(x)&0xff00000000000000ull) >> 56) | (((uint64_t)(x)&0x00ff000000000000ull) >> 40) | \
31 (((uint64_t)(x)&0x0000ff0000000000ull) >> 24) | (((uint64_t)(x)&0x000000ff00000000ull) >> 8) | \
32 (((uint64_t)(x)&0x00000000ff000000ull) << 8) | (((uint64_t)(x)&0x0000000000ff0000ull) << 24) | \
33 (((uint64_t)(x)&0x000000000000ff00ull) << 40) | (((uint64_t)(x)&0x00000000000000ffull) << 56)))
34
35struct Radix {
36public:
37 static inline bool IsLittleEndian() {
38 int n = 1;
39 if (*char_ptr_cast(src: &n) == 1) {
40 return true;
41 } else {
42 return false;
43 }
44 }
45
46 template <class T>
47 static inline void EncodeData(data_ptr_t dataptr, T value) {
48 throw NotImplementedException("Cannot create data from this type");
49 }
50
51 static inline void EncodeStringDataPrefix(data_ptr_t dataptr, string_t value, idx_t prefix_len) {
52 auto len = value.GetSize();
53 memcpy(dest: dataptr, src: value.GetData(), n: MinValue(a: len, b: prefix_len));
54 if (len < prefix_len) {
55 memset(s: dataptr + len, c: '\0', n: prefix_len - len);
56 }
57 }
58
59 static inline uint8_t FlipSign(uint8_t key_byte) {
60 return key_byte ^ 128;
61 }
62
63 static inline uint32_t EncodeFloat(float x) {
64 uint64_t buff;
65
66 //! zero
67 if (x == 0) {
68 buff = 0;
69 buff |= (1u << 31);
70 return buff;
71 }
72 // nan
73 if (Value::IsNan(input: x)) {
74 return UINT_MAX;
75 }
76 //! infinity
77 if (x > FLT_MAX) {
78 return UINT_MAX - 1;
79 }
80 //! -infinity
81 if (x < -FLT_MAX) {
82 return 0;
83 }
84 buff = Load<uint32_t>(ptr: const_data_ptr_cast(src: &x));
85 if ((buff & (1u << 31)) == 0) { //! +0 and positive numbers
86 buff |= (1u << 31);
87 } else { //! negative numbers
88 buff = ~buff; //! complement 1
89 }
90
91 return buff;
92 }
93
94 static inline uint64_t EncodeDouble(double x) {
95 uint64_t buff;
96 //! zero
97 if (x == 0) {
98 buff = 0;
99 buff += (1ull << 63);
100 return buff;
101 }
102 // nan
103 if (Value::IsNan(input: x)) {
104 return ULLONG_MAX;
105 }
106 //! infinity
107 if (x > DBL_MAX) {
108 return ULLONG_MAX - 1;
109 }
110 //! -infinity
111 if (x < -DBL_MAX) {
112 return 0;
113 }
114 buff = Load<uint64_t>(ptr: const_data_ptr_cast(src: &x));
115 if (buff < (1ull << 63)) { //! +0 and positive numbers
116 buff += (1ull << 63);
117 } else { //! negative numbers
118 buff = ~buff; //! complement 1
119 }
120 return buff;
121 }
122};
123
124template <>
125inline void Radix::EncodeData(data_ptr_t dataptr, bool value) {
126 Store<uint8_t>(val: value ? 1 : 0, ptr: dataptr);
127}
128
129template <>
130inline void Radix::EncodeData(data_ptr_t dataptr, int8_t value) {
131 Store<uint8_t>(val: value, ptr: dataptr);
132 dataptr[0] = FlipSign(key_byte: dataptr[0]);
133}
134
135template <>
136inline void Radix::EncodeData(data_ptr_t dataptr, int16_t value) {
137 Store<uint16_t>(BSWAP16(value), ptr: dataptr);
138 dataptr[0] = FlipSign(key_byte: dataptr[0]);
139}
140
141template <>
142inline void Radix::EncodeData(data_ptr_t dataptr, int32_t value) {
143 Store<uint32_t>(BSWAP32(value), ptr: dataptr);
144 dataptr[0] = FlipSign(key_byte: dataptr[0]);
145}
146
147template <>
148inline void Radix::EncodeData(data_ptr_t dataptr, int64_t value) {
149 Store<uint64_t>(BSWAP64(value), ptr: dataptr);
150 dataptr[0] = FlipSign(key_byte: dataptr[0]);
151}
152
153template <>
154inline void Radix::EncodeData(data_ptr_t dataptr, uint8_t value) {
155 Store<uint8_t>(val: value, ptr: dataptr);
156}
157
158template <>
159inline void Radix::EncodeData(data_ptr_t dataptr, uint16_t value) {
160 Store<uint16_t>(BSWAP16(value), ptr: dataptr);
161}
162
163template <>
164inline void Radix::EncodeData(data_ptr_t dataptr, uint32_t value) {
165 Store<uint32_t>(BSWAP32(value), ptr: dataptr);
166}
167
168template <>
169inline void Radix::EncodeData(data_ptr_t dataptr, uint64_t value) {
170 Store<uint64_t>(BSWAP64(value), ptr: dataptr);
171}
172
173template <>
174inline void Radix::EncodeData(data_ptr_t dataptr, hugeint_t value) {
175 EncodeData<int64_t>(dataptr, value: value.upper);
176 EncodeData<uint64_t>(dataptr: dataptr + sizeof(value.upper), value: value.lower);
177}
178
179template <>
180inline void Radix::EncodeData(data_ptr_t dataptr, float value) {
181 uint32_t converted_value = EncodeFloat(x: value);
182 Store<uint32_t>(BSWAP32(converted_value), ptr: dataptr);
183}
184
185template <>
186inline void Radix::EncodeData(data_ptr_t dataptr, double value) {
187 uint64_t converted_value = EncodeDouble(x: value);
188 Store<uint64_t>(BSWAP64(converted_value), ptr: dataptr);
189}
190
191template <>
192inline void Radix::EncodeData(data_ptr_t dataptr, interval_t value) {
193 EncodeData<int32_t>(dataptr, value: value.months);
194 dataptr += sizeof(value.months);
195 EncodeData<int32_t>(dataptr, value: value.days);
196 dataptr += sizeof(value.days);
197 EncodeData<int64_t>(dataptr, value: value.micros);
198}
199
200} // namespace duckdb
201