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