OmniSciDB  ca0c39ec8f
 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 constexpr std::array<T, N> of {1, a, a^2, a^3, ..., a^(N-1)}.
257 template <typename T, size_t N>
258 constexpr std::array<T, N> powersOf(T const a) {
259  return powersOfImpl<T>(a, std::make_index_sequence<N>{});
260 }
261 
262 // Return constexpr std::array<double, N> of {1, 1/a, 1/a^2, 1/a^3, ..., 1/a^(N-1)}.
263 template <size_t N>
264 constexpr std::array<double, N> inversePowersOf(double const a) {
265  return inversePowersOfImpl(a, std::make_index_sequence<N>{});
266 }
267 
268 // Return pow(10,x). Single-lookup for x < 20.
269 inline double power10(unsigned const x) {
270  constexpr unsigned N = 20;
271  constexpr auto pow10 = powersOf<double, N>(10.0);
272  return x < N ? pow10[x] : (pow10[N - 1] * 10) * power10(x - N);
273 }
274 
275 // Return 1/pow(10,x). Single-lookup for x < 20.
276 inline double power10inv(unsigned const x) {
277  constexpr unsigned N = 20;
278  constexpr auto pow10inv = inversePowersOf<N>(10.0);
279  return x < N ? pow10inv[x] : (pow10inv[N - 1] / 10) * power10inv(x - N);
280 }
281 
282 // May be constexpr in C++20.
283 template <typename TO, typename FROM>
284 inline TO reinterpret_bits(FROM const from) {
285  TO to{0};
286  memcpy(&to, &from, sizeof(TO) < sizeof(FROM) ? sizeof(TO) : sizeof(FROM));
287  return to;
288 }
289 
290 template <typename... STR>
291 constexpr std::array<std::string_view, sizeof...(STR)> string_view_array(STR&&... str) {
292  return {std::forward<STR>(str)...};
293 }
294 
295 template <typename OUTPUT, typename INPUT, typename FUNC>
296 OUTPUT transform(INPUT const& input, FUNC const& func) {
297  OUTPUT output;
298  output.reserve(input.size());
299  for (auto const& x : input) {
300  output.push_back(func(x));
301  }
302  return output;
303 }
304 
305 } // namespace shared
306 
308 
309 #if __cplusplus >= 202002L // C++20
310 
311 #include <bit>
312 
313 namespace shared {
314 
315 using endian = std::endian;
316 
317 } // namespace shared
318 
319 #else // __cplusplus
320 
321 #if defined(__GNUC__) || defined(__clang__) // compiler
322 
323 namespace shared {
324 
325 enum class endian {
326  little = __ORDER_LITTLE_ENDIAN__,
327  big = __ORDER_BIG_ENDIAN__,
328  native = __BYTE_ORDER__
329 };
330 
331 } // namespace shared
332 
333 #elif defined(_WIN32) // compiler
334 
335 namespace shared {
336 
337 enum class endian { little = 0, big = 1, native = little };
338 
339 } // namespace shared
340 
341 #else // compiler
342 
343 #error "unexpected compiler"
344 
345 #endif // compiler
346 
347 #endif // __cplusplus >= 202002L
348 
350 
351 #if __cplusplus >= 202002L // C++20
352 #include <version> // for __cpp_lib_byteswap
353 #endif // __cplusplus >= 202002L
354 
355 #if __cplusplus < 202002L || !defined(__cpp_lib_byteswap) // C++ standard
356 
357 #include <climits>
358 #include <utility>
359 
360 namespace shared {
361 
362 // https://stackoverflow.com/questions/36936584/how-to-write-constexpr-swap-function-to-change-endianess-of-an-integer/36937049#36937049
363 template <class T, std::size_t... N>
364 constexpr T bswap_impl(T i, std::index_sequence<N...>) {
365  return ((((i >> (N * CHAR_BIT)) & (T)(unsigned char)(-1))
366  << ((sizeof(T) - 1 - N) * CHAR_BIT)) |
367  ...);
368 };
370 constexpr U bswap(T i) {
371  return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
372 }
373 template <class T>
374 constexpr T byteswap(T n) noexcept {
375  return bswap(n);
376 }
377 
378 } // namespace shared
379 
380 #else // C++ standard
381 
382 #include <bit>
383 
384 namespace shared {
385 
386 using byteswap = std::byteswap; // expected in C++23
387 
388 } // namespace shared
389 
390 #endif // C++ standard
391 
393 
394 namespace shared {
395 
396 inline constexpr auto heavyai_htons(std::uint16_t h) {
397  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
398 }
399 
400 inline constexpr auto heavyai_htonl(std::uint32_t h) {
401  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
402 }
403 
404 inline constexpr auto heavyai_htonll(std::uint64_t h) {
405  return (shared::endian::native == shared::endian::big) ? h : shared::byteswap(h);
406 }
407 
408 inline constexpr auto heavyai_ntohs(std::uint16_t n) {
409  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
410 }
411 
412 inline constexpr auto heavyai_ntohl(std::uint32_t n) {
413  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
414 }
415 
416 inline constexpr auto heavyai_ntohll(std::uint64_t n) {
417  return (shared::endian::native == shared::endian::big) ? n : shared::byteswap(n);
418 }
419 
420 } // namespace shared
bool contains(const T &container, const U &element)
Definition: misc.h:195
double power10(unsigned const x)
Definition: misc.h:269
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:284
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:264
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:416
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:408
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:400
#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:404
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:296
double power10inv(unsigned const x)
Definition: misc.h:276
constexpr std::array< std::string_view, sizeof...(STR)> string_view_array(STR &&...str)
Definition: misc.h:291
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:364
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:370
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
constexpr unsigned N
Definition: Utm.h:110
#define CHECK(condition)
Definition: Logger.h:222
constexpr auto heavyai_ntohl(std::uint32_t n)
Definition: misc.h:412
int64_t rem
Definition: misc.h:172
constexpr T byteswap(T n) noexcept
Definition: misc.h:374
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:396
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:1000
constexpr std::array< T, N > powersOf(T const a)
Definition: misc.h:258
DivUMod divUMod(int64_t num, int64_t den)
Definition: misc.h:176