OmniSciDB  a987f07e93
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
misc.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "funcannotations.h"
20 
21 #include <array>
22 #include <cstdint>
23 #include <cstring>
24 #include <deque>
25 #include <iterator>
26 #include <list>
27 #include <map>
28 #include <set>
29 #include <string_view>
30 #include <unordered_set>
31 #include <vector>
32 
33 class SQLTypeInfo;
34 
35 namespace {
36 
37 template <typename T>
38 constexpr T power(T const a, T const n) {
39  return n ? a * power(a, n - 1) : static_cast<T>(1);
40 }
41 
42 template <typename T, size_t... Indices>
43 constexpr std::array<T, sizeof...(Indices)> powersOfImpl(
44  T const a,
45  std::index_sequence<Indices...>) {
46  return {power(a, static_cast<T>(Indices))...};
47 }
48 
49 template <size_t... Indices>
50 constexpr std::array<double, sizeof...(Indices)> inversePowersOfImpl(
51  double const a,
52  std::index_sequence<Indices...>) {
53  return {(1.0 / power(a, static_cast<double>(Indices)))...};
54 }
55 
56 } // namespace
57 
58 namespace shared {
59 
60 template <typename K, typename V, typename comp>
61 V& get_from_map(std::map<K, V, comp>& map, const K& key) {
62  auto find_it = map.find(key);
63  CHECK(find_it != map.end());
64  return find_it->second;
65 }
66 
67 template <typename K, typename V, typename comp>
68 const V& get_from_map(const std::map<K, V, comp>& map, const K& key) {
69  auto find_it = map.find(key);
70  CHECK(find_it != map.end());
71  return find_it->second;
72 }
73 
74 // source is destructively appended to the back of destination.
75 // Return number of elements appended.
76 template <typename T>
77 size_t append_move(std::vector<T>& destination, std::vector<T>&& source) {
78  if (source.empty()) {
79  return 0;
80  } else if (destination.empty()) {
81  destination = std::move(source);
82  return destination.size();
83  } else {
84  size_t const source_size = source.size();
85  destination.reserve(destination.size() + source_size);
86  std::move(std::begin(source), std::end(source), std::back_inserter(destination));
87  return source_size;
88  }
89 }
90 
91 template <typename... Ts, typename T>
92 bool dynamic_castable_to_any(T const* ptr) {
93  return (... || dynamic_cast<Ts const*>(ptr));
94 }
95 
96 // Helper to print out contents of simple containers (e.g. vector, list, deque)
97 // including nested containers, e.g. 2d vectors, list of vectors, etc.
98 // Base value_type must be a std::is_scalar_v type, though you can add custom
99 // objects below with a new `else if constexpr` block.
100 // Example: VLOG(1) << "container=" << shared::printContainer(container);
101 template <typename CONTAINER>
103  CONTAINER& container;
104 };
105 
106 template <typename CONTAINER>
108  return {container};
109 }
110 
111 template <typename CONTAINER>
112 struct is_std_container : std::false_type {};
113 template <typename T, typename A>
114 struct is_std_container<std::deque<T, A> > : std::true_type {};
115 template <typename T, typename A>
116 struct is_std_container<std::list<T, A> > : std::true_type {};
117 template <typename T, typename A>
118 struct is_std_container<std::set<T, A> > : std::true_type {};
119 template <typename T, typename A>
120 struct is_std_container<std::unordered_set<T, A> > : std::true_type {};
121 template <typename T, typename A>
122 struct is_std_container<std::vector<T, A> > : std::true_type {};
123 
124 template <typename OSTREAM, typename CONTAINER>
125 OSTREAM& operator<<(OSTREAM& os, PrintContainer<CONTAINER> pc) {
126  if (pc.container.empty()) {
127  return os << "()";
128  } else {
130  os << '(';
131  for (auto& container : pc.container) {
132  os << printContainer(container);
133  }
134  } else {
135  for (auto itr = pc.container.begin(); itr != pc.container.end(); ++itr) {
136  if constexpr (std::is_pointer_v<typename CONTAINER::value_type>) { // NOLINT
137  os << (itr == pc.container.begin() ? '(' : ' ') << (void const*)*itr;
138  } else {
139  os << (itr == pc.container.begin() ? '(' : ' ') << *itr;
140  }
141  }
142  }
143  return os << ')';
144  }
145 }
146 
147 // Same as strftime(buf, max, "%F", tm) but guarantees that the year is
148 // zero-padded to a minimum length of 4. Return the number of characters
149 // written, not including null byte. If max is not large enough, return 0.
150 size_t formatDate(char* buf, size_t const max, int64_t const unixtime);
151 
152 // Same as strftime(buf, max, "%F %T", tm) but guarantees that the year is
153 // zero-padded to a minimum length of 4. Return the number of characters
154 // written, not including null byte. If max is not large enough, return 0.
155 // Requirement: 0 <= dimension <= 9.
156 size_t formatDateTime(char* buf,
157  size_t const max,
158  int64_t const timestamp,
159  int const dimension,
160  bool use_iso_format = false);
161 
162 // Write unixtime in seconds since epoch as "HH:MM:SS" format.
163 size_t formatHMS(char* buf, size_t const max, int64_t const unixtime);
164 
165 // Write unix time in seconds since epoch as ISO 8601 format for the given temporal type.
166 std::string convert_temporal_to_iso_format(const SQLTypeInfo& type_info,
167  int64_t unix_time);
168 
169 // Result of division where quot is floored and rem is unsigned.
170 struct DivUMod {
171  int64_t quot;
172  int64_t rem;
173 };
174 
175 // Requirement: 0 < den
176 inline DivUMod divUMod(int64_t num, int64_t den) {
177  DivUMod div{num / den, num % den};
178  if (div.rem < 0) {
179  --div.quot;
180  div.rem += den;
181  }
182  return div;
183 }
184 
185 // Requirement: 0 < den.
186 inline uint64_t unsignedMod(int64_t num, int64_t den) {
187  int64_t mod = num % den;
188  if (mod < 0) {
189  mod += den;
190  }
191  return mod;
192 }
193 
194 template <typename T, typename U>
195 inline bool contains(const T& container, const U& element) {
196  if (std::find(container.begin(), container.end(), element) == container.end()) {
197  return false;
198  } else {
199  return true;
200  }
201 }
202 
203 // Calculate polynomial c0 + c1*x + c2*x^2 + ... + cn*x^n using Horner's method.
204 template <typename... COEFFICIENTS>
205 DEVICE constexpr double horner(double const x, double const c0, COEFFICIENTS... c) {
206  if constexpr (sizeof...(COEFFICIENTS) == 0) { // NOLINT
207  return c0;
208  } else {
209  return horner(x, c...) * x + c0;
210  }
211  return {}; // quiet nvcc warning https://stackoverflow.com/a/64561686/2700898
212 }
213 
214 // OK for -0.15 <= x <= 0.15
215 DEVICE inline double fastAtanh(double const x) {
216  // Mathematica: CoefficientList[Normal@Series[ArcTanh[x],{x,0,16}],x] // InputForm
217  return x * horner(x * x, 1, 1 / 3., 1 / 5., 1 / 7., 1 / 9., 1 / 11., 1 / 13., 1 / 15.);
218 }
219 
220 // OK for -1 <= x <= 1
221 DEVICE inline double fastCos(double const x) {
222  // Mathematica: CoefficientList[Normal@Series[Cos[x],{x,0,16}],x] // InputForm
223  // clang-format off
224  return horner(x * x, 1, -1/2., 1/24., -1/720., 1/40320., -1/3628800.,
225  1/479001600., -1/87178291200., 1/20922789888000.);
226  // clang-format on
227 }
228 
229 // OK for -1 <= x <= 1
230 DEVICE inline double fastCosh(double const x) {
231  // Mathematica: CoefficientList[Normal@Series[Cosh[x],{x,0,16}],x] // InputForm
232  // clang-format off
233  return horner(x * x, 1, 1/2., 1/24., 1/720., 1/40320., 1/3628800.,
234  1/479001600., 1/87178291200., 1/20922789888000.);
235  // clang-format on
236 }
237 
238 // OK for -1 <= x <= 1
239 DEVICE inline double fastSin(double const x) {
240  // Mathematica: CoefficientList[Normal@Series[Sin[x],{x,0,16}],x] // InputForm
241  // clang-format off
242  return x * horner(x * x, 1, -1/6., 1/120., -1/5040., 1/362880.,
243  -1/39916800., 1/6227020800., -1/1307674368000.);
244  // clang-format on
245 }
246 
247 // OK for -1 <= x <= 1
248 DEVICE inline double fastSinh(double const x) {
249  // Mathematica: CoefficientList[Normal@Series[Sinh[x],{x,0,16}],x] // InputForm
250  // clang-format off
251  return x * horner(x * x, 1, 1/6., 1/120., 1/5040., 1/362880.,
252  1/39916800., 1/6227020800., 1/1307674368000.);
253  // clang-format on
254 }
255 
256 // Return true if value is equal to any of the other (enum) values.
257 template <int... values, typename T>
258 inline bool is_any(T&& value) {
259  return (... || (values == value));
260 }
261 
262 // Return constexpr std::array<T, N> of {1, a, a^2, a^3, ..., a^(N-1)}.
263 template <typename T, size_t N>
264 constexpr std::array<T, N> powersOf(T const a) {
265  return powersOfImpl<T>(a, std::make_index_sequence<N>{});
266 }
267 
268 // Return constexpr std::array<double, N> of {1, 1/a, 1/a^2, 1/a^3, ..., 1/a^(N-1)}.
269 template <size_t N>
270 constexpr std::array<double, N> inversePowersOf(double const a) {
271  return inversePowersOfImpl(a, std::make_index_sequence<N>{});
272 }
273 
274 // Return pow(10,x). Single-lookup for x < 20.
275 inline double power10(unsigned const x) {
276  constexpr unsigned N = 20;
277  constexpr auto pow10 = powersOf<double, N>(10.0);
278  return x < N ? pow10[x] : (pow10[N - 1] * 10) * power10(x - N);
279 }
280 
281 // Return 1/pow(10,x). Single-lookup for x < 20.
282 inline double power10inv(unsigned const x) {
283  constexpr unsigned N = 20;
284  constexpr auto pow10inv = inversePowersOf<N>(10.0);
285  return x < N ? pow10inv[x] : (pow10inv[N - 1] / 10) * power10inv(x - N);
286 }
287 
288 // Deprecated - use shared::bit_cast() instead.
289 // TODO replace all calls to reinterpret_bits() w/ shared::bit_cast().
290 template <typename TO, typename FROM>
291 inline TO reinterpret_bits(FROM const from) {
292  TO to{0};
293  memcpy(&to, &from, sizeof(TO) < sizeof(FROM) ? sizeof(TO) : sizeof(FROM));
294  return to;
295 }
296 
297 template <typename TO, typename FROM>
298 inline TO bit_cast(FROM&& from) {
299 #if 202002L <= __cplusplus // C++20
300  if constexpr (sizeof(TO) <= sizeof(FROM)) {
301  return std::bit_cast<TO>(std::forward<FROM>(from));
302  } else {
303  TO to{0}; // std::bit_cast() has the undesirable feature of indeterminate bits.
304  memcpy(&to, &from, sizeof(FROM));
305  return to;
306  }
307 #else
308  TO to{0};
309  memcpy(&to, &from, sizeof(TO) < sizeof(FROM) ? sizeof(TO) : sizeof(FROM));
310  return to;
311 #endif
312 }
313 
314 template <typename... STR>
315 constexpr std::array<std::string_view, sizeof...(STR)> string_view_array(STR&&... str) {
316  return {std::forward<STR>(str)...};
317 }
318 
319 template <typename OUTPUT, typename INPUT, typename FUNC>
320 OUTPUT transform(INPUT const& input, FUNC const& func) {
321  OUTPUT output;
322  output.reserve(input.size());
323  for (auto const& x : input) {
324  output.push_back(func(x));
325  }
326  return output;
327 }
328 
329 inline unsigned ceil_div(unsigned const dividend, unsigned const divisor) {
330  return (dividend + (divisor - 1)) / divisor;
331 }
332 
333 } // namespace shared
334 
336 
337 #if __cplusplus >= 202002L // C++20
338 
339 #include <bit>
340 
341 namespace shared {
342 
343 using endian = std::endian;
344 
345 } // namespace shared
346 
347 #else // __cplusplus
348 
349 #if defined(__GNUC__) || defined(__clang__) // compiler
350 
351 namespace shared {
352 
353 enum class endian {
354  little = __ORDER_LITTLE_ENDIAN__,
355  big = __ORDER_BIG_ENDIAN__,
356  native = __BYTE_ORDER__
357 };
358 
359 } // namespace shared
360 
361 #elif defined(_WIN32) // compiler
362 
363 namespace shared {
364 
365 enum class endian { little = 0, big = 1, native = little };
366 
367 } // namespace shared
368 
369 #else // compiler
370 
371 #error "unexpected compiler"
372 
373 #endif // compiler
374 
375 #endif // __cplusplus >= 202002L
376 
378 
379 #if __cplusplus >= 202002L // C++20
380 #include <version> // for __cpp_lib_byteswap
381 #endif // __cplusplus >= 202002L
382 
383 #if __cplusplus < 202002L || !defined(__cpp_lib_byteswap) // C++ standard
384 
385 #include <climits>
386 #include <utility>
387 
388 namespace shared {
389 
390 // https://stackoverflow.com/questions/36936584/how-to-write-constexpr-swap-function-to-change-endianess-of-an-integer/36937049#36937049
391 template <class T, std::size_t... N>
392 constexpr T bswap_impl(T i, std::index_sequence<N...>) {
393  return ((((i >> (N * CHAR_BIT)) & (T)(unsigned char)(-1))
394  << ((sizeof(T) - 1 - N) * CHAR_BIT)) |
395  ...);
396 };
398 constexpr U bswap(T i) {
399  return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
400 }
401 template <class T>
402 constexpr T byteswap(T n) noexcept {
403  return bswap(n);
404 }
405 
406 } // namespace shared
407 
408 #else // C++ standard
409 
410 #include <bit>
411 
412 namespace shared {
413 
414 using byteswap = std::byteswap; // expected in C++23
415 
416 } // namespace shared
417 
418 #endif // C++ standard
419 
421 
422 namespace shared {
423 
424 inline constexpr auto heavyai_htons(std::uint16_t h) {
425  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
426 }
427 
428 inline constexpr auto heavyai_htonl(std::uint32_t h) {
429  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
430 }
431 
432 inline constexpr auto heavyai_htonll(std::uint64_t h) {
433  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
434 }
435 
436 inline constexpr auto heavyai_ntohs(std::uint16_t n) {
437  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
438 }
439 
440 inline constexpr auto heavyai_ntohl(std::uint32_t n) {
441  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
442 }
443 
444 inline constexpr auto heavyai_ntohll(std::uint64_t n) {
445  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
446 }
447 
448 } // namespace shared
bool contains(const T &container, const U &element)
Definition: misc.h:195
double power10(unsigned const x)
Definition: misc.h:275
DEVICE constexpr double horner(double const x, double const c0, COEFFICIENTS...c)
Definition: misc.h:205
TO reinterpret_bits(FROM const from)
Definition: misc.h:291
unsigned ceil_div(unsigned const dividend, unsigned const divisor)
Definition: misc.h:329
int64_t quot
Definition: misc.h:171
DEVICE double fastSin(double const x)
Definition: misc.h:239
std::string convert_temporal_to_iso_format(const SQLTypeInfo &type_info, int64_t unix_time)
Definition: misc.cpp:109
constexpr std::array< double, N > inversePowersOf(double const a)
Definition: misc.h:270
EXTENSION_NOINLINE double power(const double x, const double y)
DEVICE double fastCos(double const x)
Definition: misc.h:221
constexpr auto heavyai_ntohll(std::uint64_t n)
Definition: misc.h:444
constexpr std::array< T, sizeof...(Indices)> powersOfImpl(T const a, std::index_sequence< Indices...>)
Definition: misc.h:43
constexpr auto heavyai_ntohs(std::uint16_t n)
Definition: misc.h:436
size_t formatHMS(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:96
constexpr auto heavyai_htonl(std::uint32_t h)
Definition: misc.h:428
#define DEVICE
constexpr double a
Definition: Utm.h:32
size_t append_move(std::vector< T > &destination, std::vector< T > &&source)
Definition: misc.h:77
constexpr std::array< double, sizeof...(Indices)> inversePowersOfImpl(double const a, std::index_sequence< Indices...>)
Definition: misc.h:50
constexpr auto heavyai_htonll(std::uint64_t h)
Definition: misc.h:432
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:320
double power10inv(unsigned const x)
Definition: misc.h:282
constexpr std::array< std::string_view, sizeof...(STR)> string_view_array(STR &&...str)
Definition: misc.h:315
CONTAINER & container
Definition: misc.h:103
size_t formatDate(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:27
constexpr T bswap_impl(T i, std::index_sequence< N...>)
Definition: misc.h:392
V & get_from_map(std::map< K, V, comp > &map, const K &key)
Definition: misc.h:61
constexpr U bswap(T i)
Definition: misc.h:398
DEVICE double fastAtanh(double const x)
Definition: misc.h:215
uint64_t unsignedMod(int64_t num, int64_t den)
Definition: misc.h:186
size_t formatDateTime(char *buf, size_t const max, int64_t const timestamp, int const dimension, bool use_iso_format)
Definition: misc.cpp:45
TO bit_cast(FROM &&from)
Definition: misc.h:298
constexpr unsigned N
Definition: Utm.h:110
#define CHECK(condition)
Definition: Logger.h:289
constexpr auto heavyai_ntohl(std::uint32_t n)
Definition: misc.h:440
int64_t rem
Definition: misc.h:172
constexpr T byteswap(T n) noexcept
Definition: misc.h:402
bool is_any() const
Definition: sqltypes.h:573
bool dynamic_castable_to_any(T const *ptr)
Definition: misc.h:92
PrintContainer< CONTAINER > printContainer(CONTAINER &container)
Definition: misc.h:107
constexpr double n
Definition: Utm.h:38
constexpr auto heavyai_htons(std::uint16_t h)
Definition: misc.h:424
DEVICE double fastCosh(double const x)
Definition: misc.h:230
DEVICE double fastSinh(double const x)
Definition: misc.h:248
int dimension
Definition: sqltypes.h:1008
constexpr std::array< T, N > powersOf(T const a)
Definition: misc.h:264
DivUMod divUMod(int64_t num, int64_t den)
Definition: misc.h:176