1 /**
2  * @file   utils.cc
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  * @copyright Copyright (c) 2016 MIT and Intel Corporation
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  *
29  * @section DESCRIPTION
30  *
31  * This file implements useful (global) functions.
32  */
33 
34 #include "tiledb/sm/misc/utils.h"
35 #include "tiledb/common/logger.h"
36 #include "tiledb/sm/enums/datatype.h"
37 #include "tiledb/sm/enums/serialization_type.h"
38 #include "tiledb/sm/misc/constants.h"
39 #include "tiledb/sm/misc/uri.h"
40 
41 #include <algorithm>
42 #include <iostream>
43 #include <set>
44 #include <sstream>
45 
46 #ifdef _WIN32
47 #include <sys/timeb.h>
48 #include <sys/types.h>
49 #else
50 #include <sys/time.h>
51 #endif
52 
53 #ifdef __linux__
54 #include "tiledb/sm/filesystem/posix.h"
55 #endif
56 
57 using namespace tiledb::common;
58 
59 namespace tiledb {
60 namespace sm {
61 
62 namespace utils {
63 
64 #ifdef __linux__
65 namespace https {
find_ca_certs_linux(const Posix & posix)66 std::string find_ca_certs_linux(const Posix& posix) {
67   // Check ever cert file location to see if the certificate exists
68   for (const std::string& cert : constants::cert_files_linux) {
69     // Check if the file exists, any errors are treated as the file not existing
70     if (posix.is_file(cert)) {
71       return cert;
72     }
73   }
74   // Could not find the ca bundle
75   return "";
76 }
77 }  // namespace https
78 #endif
79 
80 namespace parse {
81 
82 /* ********************************* */
83 /*          PARSING FUNCTIONS        */
84 /* ********************************* */
85 
convert(const std::string & str,int * value)86 Status convert(const std::string& str, int* value) {
87   if (!is_int(str)) {
88     auto errmsg = std::string("Failed to convert string '") + str +
89                   "' to int; Invalid argument";
90     return LOG_STATUS(Status::UtilsError(errmsg));
91   }
92 
93   try {
94     *value = std::stoi(str);
95   } catch (std::invalid_argument& e) {
96     auto errmsg = std::string("Failed to convert string '") + str +
97                   "' to int; Invalid argument";
98     return LOG_STATUS(Status::UtilsError(errmsg));
99   } catch (std::out_of_range& e) {
100     auto errmsg = std::string("Failed to convert string '") + str +
101                   "' to int; Value out of range";
102     return LOG_STATUS(Status::UtilsError(errmsg));
103   }
104 
105   return Status::Ok();
106 }
107 
convert(const std::string & str,uint32_t * value)108 Status convert(const std::string& str, uint32_t* value) {
109   if (!is_uint(str)) {
110     auto errmsg = std::string("Failed to convert string '") + str +
111                   "' to uint32_t; Invalid argument";
112     return LOG_STATUS(Status::UtilsError(errmsg));
113   }
114 
115   try {
116     auto v = std::stoul(str);
117     if (v > UINT32_MAX)
118       throw std::out_of_range("Cannot convert long to unsigned int");
119     *value = (uint32_t)v;
120   } catch (std::invalid_argument& e) {
121     auto errmsg = std::string("Failed to convert string '") + str +
122                   "' to uint32_t; Invalid argument";
123     return LOG_STATUS(Status::UtilsError(errmsg));
124   } catch (std::out_of_range& e) {
125     auto errmsg = std::string("Failed to convert string '") + str +
126                   "' to uint32_t; Value out of range";
127     return LOG_STATUS(Status::UtilsError(errmsg));
128   }
129 
130   return Status::Ok();
131 }
132 
convert(const std::string & str,uint64_t * value)133 Status convert(const std::string& str, uint64_t* value) {
134   if (!is_uint(str)) {
135     auto errmsg = std::string("Failed to convert string '") + str +
136                   "' to uint64_t; Invalid argument";
137     return LOG_STATUS(Status::UtilsError(errmsg));
138   }
139 
140   try {
141     *value = std::stoull(str);
142   } catch (std::invalid_argument& e) {
143     auto errmsg = std::string("Failed to convert string '") + str +
144                   "' to uint64_t; Invalid argument";
145     return LOG_STATUS(Status::UtilsError(errmsg));
146   } catch (std::out_of_range& e) {
147     auto errmsg = std::string("Failed to convert string '") + str +
148                   "' to uint64_t; Value out of range";
149     return LOG_STATUS(Status::UtilsError(errmsg));
150   }
151 
152   return Status::Ok();
153 }
154 
convert(const std::string & str,int64_t * value)155 Status convert(const std::string& str, int64_t* value) {
156   if (!is_int(str)) {
157     auto errmsg = std::string("Failed to convert string '") + str +
158                   "' to int64_t; Invalid argument";
159     return LOG_STATUS(Status::UtilsError(errmsg));
160   }
161 
162   try {
163     *value = std::stoll(str);
164   } catch (std::invalid_argument& e) {
165     auto errmsg = std::string("Failed to convert string '") + str +
166                   "' to int64_t; Invalid argument";
167     return LOG_STATUS(Status::UtilsError(errmsg));
168   } catch (std::out_of_range& e) {
169     auto errmsg = std::string("Failed to convert string '") + str +
170                   "' to int64_t; Value out of range";
171     return LOG_STATUS(Status::UtilsError(errmsg));
172   }
173 
174   return Status::Ok();
175 }
176 
convert(const std::string & str,float * value)177 Status convert(const std::string& str, float* value) {
178   try {
179     *value = std::stof(str);
180   } catch (std::invalid_argument& e) {
181     return LOG_STATUS(Status::UtilsError(
182         "Failed to convert string to float32_t; Invalid argument"));
183   } catch (std::out_of_range& e) {
184     return LOG_STATUS(Status::UtilsError(
185         "Failed to convert string to float32_t; Value out of range"));
186   }
187 
188   return Status::Ok();
189 }
190 
convert(const std::string & str,double * value)191 Status convert(const std::string& str, double* value) {
192   try {
193     *value = std::stod(str);
194   } catch (std::invalid_argument& e) {
195     return LOG_STATUS(Status::UtilsError(
196         "Failed to convert string to float64_t; Invalid argument"));
197   } catch (std::out_of_range& e) {
198     return LOG_STATUS(Status::UtilsError(
199         "Failed to convert string to float64_t; Value out of range"));
200   }
201 
202   return Status::Ok();
203 }
204 
convert(const std::string & str,bool * value)205 Status convert(const std::string& str, bool* value) {
206   std::string lvalue = str;
207   std::transform(lvalue.begin(), lvalue.end(), lvalue.begin(), ::tolower);
208   if (lvalue == "true") {
209     *value = true;
210   } else if (lvalue == "false") {
211     *value = false;
212   } else {
213     return LOG_STATUS(Status::UtilsError(
214         "Failed to convert string to bool; Value not 'true' or 'false'"));
215   }
216 
217   return Status::Ok();
218 }
219 
convert(const std::string & str,SerializationType * value)220 Status convert(const std::string& str, SerializationType* value) {
221   std::string lvalue = str;
222   std::transform(lvalue.begin(), lvalue.end(), lvalue.begin(), ::tolower);
223   if (lvalue == "json") {
224     *value = SerializationType::JSON;
225   } else if (lvalue == "capnp") {
226     *value = SerializationType::CAPNP;
227   } else {
228     return LOG_STATUS(
229         Status::UtilsError("Failed to convert string to SerializationType; "
230                            "Value not 'json' or 'capnp'"));
231   }
232 
233   return Status::Ok();
234 }
235 
get_timestamp_range(const URI & uri,std::pair<uint64_t,uint64_t> * timestamp_range)236 Status get_timestamp_range(
237     const URI& uri, std::pair<uint64_t, uint64_t>* timestamp_range) {
238   // Initializations
239   auto name = uri.remove_trailing_slash().last_path_part();
240   *timestamp_range = {0, 0};
241 
242   // Cut the suffix
243   auto pos = name.find_last_of('.');
244   name = (pos == std::string::npos) ? name : name.substr(0, pos);
245 
246   // Get fragment version
247   uint32_t version = 0;
248   RETURN_NOT_OK(utils::parse::get_fragment_name_version(name, &version));
249 
250   if (version == 1) {  // This is equivalent to format version <=2
251     assert(name.find_last_of('_') != std::string::npos);
252     auto t_str = name.substr(name.find_last_of('_') + 1);
253     sscanf(
254         t_str.c_str(),
255         (std::string("%") + std::string(PRId64)).c_str(),
256         (long long int*)&timestamp_range->first);
257     timestamp_range->second = timestamp_range->first;
258   } else {
259     assert(name.find_last_of('_') != std::string::npos);
260     sscanf(
261         name.c_str(),
262         (std::string("__%") + std::string(PRId64) + "_%" + std::string(PRId64))
263             .c_str(),
264         (long long int*)&timestamp_range->first,
265         (long long int*)&timestamp_range->second);
266   }
267 
268   return Status::Ok();
269 }
270 
get_fragment_name_version(const std::string & name,uint32_t * version)271 Status get_fragment_name_version(const std::string& name, uint32_t* version) {
272   // First check if it is version 3 or greater, which has 5 '_'
273   // characters in the name.
274   size_t n = std::count(name.begin(), name.end(), '_');
275   if (n == 5) {
276     // Fetch the fragment version from the fragment name. If the fragment
277     // version is greater than or equal to 10, we have a footer version of 5.
278     // version is greater than or equal to 7, we have a footer version of 4.
279     // Otherwise, it is version 3.
280     const int frag_version = std::stoi(name.substr(name.find_last_of('_') + 1));
281     if (frag_version >= 10)
282       *version = 5;
283     else if (frag_version >= 7)
284       *version = 4;
285     else
286       *version = 3;
287     return Status::Ok();
288   }
289 
290   // Check if it is in version 1 or 2
291   // Version 2 has the 32-byte long UUID at the end
292   auto t_str = name.substr(name.find_last_of('_') + 1);
293   *version = (t_str.size() == 32) ? 2 : 1;
294 
295   return Status::Ok();
296 }
297 
get_fragment_version(const std::string & name,uint32_t * version)298 Status get_fragment_version(const std::string& name, uint32_t* version) {
299   uint32_t name_version;
300   RETURN_NOT_OK(get_fragment_name_version(name, &name_version));
301 
302   if (name_version <= 2) {
303     *version = UINT32_MAX;
304   } else {  // name version >= 3
305     auto v_str = name.substr(name.find_last_of('_') + 1);
306     std::stringstream ss(v_str);
307     ss >> *version;
308   }
309 
310   return Status::Ok();
311 }
312 
is_int(const std::string & str)313 bool is_int(const std::string& str) {
314   // Check if empty
315   if (str.empty())
316     return false;
317 
318   // Check first character
319   if (str[0] != '+' && str[0] != '-' && !(bool)isdigit(str[0]))
320     return false;
321 
322   // Check rest of characters
323   for (size_t i = 1; i < str.size(); ++i)
324     if (!(bool)isdigit(str[i]))
325       return false;
326 
327   return true;
328 }
329 
is_uint(const std::string & str)330 bool is_uint(const std::string& str) {
331   // Check if empty
332   if (str.empty())
333     return false;
334 
335   // Check first character
336   if (str[0] != '+' && !isdigit(str[0]))
337     return false;
338 
339   // Check characters
340   for (size_t i = 1; i < str.size(); ++i)
341     if (!(bool)isdigit(str[i]))
342       return false;
343 
344   return true;
345 }
346 
starts_with(const std::string & value,const std::string & prefix)347 bool starts_with(const std::string& value, const std::string& prefix) {
348   if (prefix.size() > value.size())
349     return false;
350   return std::equal(prefix.begin(), prefix.end(), value.begin());
351 }
352 
ends_with(const std::string & value,const std::string & suffix)353 bool ends_with(const std::string& value, const std::string& suffix) {
354   if (suffix.size() > value.size())
355     return false;
356   return value.compare(value.size() - suffix.size(), suffix.size(), suffix) ==
357          0;
358 }
359 
360 template <class T>
to_str(const T & value)361 std::string to_str(const T& value) {
362   std::stringstream ss;
363   ss << value;
364   return ss.str();
365 }
366 
to_str(const void * value,Datatype type)367 std::string to_str(const void* value, Datatype type) {
368   std::stringstream ss;
369   switch (type) {
370     case Datatype::INT8:
371       ss << *(const int8_t*)value;
372       break;
373     case Datatype::UINT8:
374       ss << *(const uint8_t*)value;
375       break;
376     case Datatype::INT16:
377       ss << *(const int16_t*)value;
378       break;
379     case Datatype::UINT16:
380       ss << *(const uint16_t*)value;
381       break;
382     case Datatype::INT32:
383       ss << *(const int32_t*)value;
384       break;
385     case Datatype::UINT32:
386       ss << *(const uint32_t*)value;
387       break;
388     case Datatype::INT64:
389       ss << *(const int64_t*)value;
390       break;
391     case Datatype::UINT64:
392       ss << *(const uint64_t*)value;
393       break;
394     case Datatype::FLOAT32:
395       ss << *(const float*)value;
396       break;
397     case Datatype::FLOAT64:
398       ss << *(const double*)value;
399       break;
400     case Datatype::CHAR:
401       ss << *(const char*)value;
402       break;
403     case Datatype::ANY:
404       ss << *(const uint8_t*)value;
405       break;
406     case Datatype::STRING_ASCII:
407       ss << *(const uint8_t*)value;
408       break;
409     case Datatype::STRING_UTF8:
410       ss << *(const uint8_t*)value;
411       break;
412     case Datatype::STRING_UTF16:
413       ss << *(const uint16_t*)value;
414       break;
415     case Datatype::STRING_UTF32:
416       ss << *(const uint32_t*)value;
417       break;
418     case Datatype::STRING_UCS2:
419       ss << *(const uint16_t*)value;
420       break;
421     case Datatype::STRING_UCS4:
422       ss << *(const uint32_t*)value;
423       break;
424     case Datatype::DATETIME_YEAR:
425     case Datatype::DATETIME_MONTH:
426     case Datatype::DATETIME_WEEK:
427     case Datatype::DATETIME_DAY:
428     case Datatype::DATETIME_HR:
429     case Datatype::DATETIME_MIN:
430     case Datatype::DATETIME_SEC:
431     case Datatype::DATETIME_MS:
432     case Datatype::DATETIME_US:
433     case Datatype::DATETIME_NS:
434     case Datatype::DATETIME_PS:
435     case Datatype::DATETIME_FS:
436     case Datatype::DATETIME_AS:
437     case Datatype::TIME_HR:
438     case Datatype::TIME_MIN:
439     case Datatype::TIME_SEC:
440     case Datatype::TIME_MS:
441     case Datatype::TIME_US:
442     case Datatype::TIME_NS:
443     case Datatype::TIME_PS:
444     case Datatype::TIME_FS:
445     case Datatype::TIME_AS:
446       ss << *(const int64_t*)value;
447       break;
448     default:
449       assert(false);
450   }
451 
452   return ss.str();
453 }
454 
common_prefix_size(const std::string & a,const std::string & b)455 uint64_t common_prefix_size(const std::string& a, const std::string& b) {
456   auto size = std::min(a.size(), b.size());
457   for (size_t i = 0; i < size; ++i) {
458     if (a[i] != b[i])
459       return i;
460   }
461 
462   return size;
463 }
464 
465 }  // namespace parse
466 
467 /* ****************************** */
468 /*         TYPE FUNCTIONS         */
469 /* ****************************** */
470 
471 namespace datatype {
472 
473 template <>
check_template_type_to_datatype(Datatype datatype)474 Status check_template_type_to_datatype<int8_t>(Datatype datatype) {
475   if (datatype == Datatype::INT8)
476     return Status::Ok();
477   return Status::Error(
478       "Template of type int8_t but datatype is not Datatype::INT8");
479 }
480 template <>
check_template_type_to_datatype(Datatype datatype)481 Status check_template_type_to_datatype<uint8_t>(Datatype datatype) {
482   if (datatype == Datatype::UINT8)
483     return Status::Ok();
484   else if (datatype == Datatype::STRING_ASCII)
485     return Status::Ok();
486   else if (datatype == Datatype::STRING_UTF8)
487     return Status::Ok();
488 
489   return Status::Error(
490       "Template of type uint8_t but datatype is not Datatype::UINT8 nor "
491       "Datatype::STRING_ASCII nor atatype::STRING_UTF8");
492 }
493 template <>
check_template_type_to_datatype(Datatype datatype)494 Status check_template_type_to_datatype<int16_t>(Datatype datatype) {
495   if (datatype == Datatype::INT16)
496     return Status::Ok();
497   return Status::Error(
498       "Template of type int16_t but datatype is not Datatype::INT16");
499 }
500 template <>
check_template_type_to_datatype(Datatype datatype)501 Status check_template_type_to_datatype<uint16_t>(Datatype datatype) {
502   if (datatype == Datatype::UINT16)
503     return Status::Ok();
504   else if (datatype == Datatype::STRING_UTF16)
505     return Status::Ok();
506   else if (datatype == Datatype::STRING_UCS2)
507     return Status::Ok();
508   return Status::Error(
509       "Template of type uint16_t but datatype is not Datatype::UINT16 nor "
510       "Datatype::STRING_UTF16 nor Datatype::STRING_UCS2");
511 }
512 template <>
check_template_type_to_datatype(Datatype datatype)513 Status check_template_type_to_datatype<int32_t>(Datatype datatype) {
514   if (datatype == Datatype::INT32)
515     return Status::Ok();
516   return Status::Error(
517       "Template of type int32_t but datatype is not Datatype::INT32");
518 }
519 template <>
check_template_type_to_datatype(Datatype datatype)520 Status check_template_type_to_datatype<uint32_t>(Datatype datatype) {
521   if (datatype == Datatype::UINT32)
522     return Status::Ok();
523   else if (datatype == Datatype::STRING_UTF32)
524     return Status::Ok();
525   else if (datatype == Datatype::STRING_UCS4)
526     return Status::Ok();
527   return Status::Error(
528       "Template of type uint32_t but datatype is not Datatype::UINT32 nor "
529       "Datatype::STRING_UTF32 nor Datatype::STRING_UCS4");
530 }
531 template <>
check_template_type_to_datatype(Datatype datatype)532 Status check_template_type_to_datatype<int64_t>(Datatype datatype) {
533   if (datatype == Datatype::INT64)
534     return Status::Ok();
535   return Status::Error(
536       "Template of type int64_t but datatype is not Datatype::INT64");
537 }
538 template <>
check_template_type_to_datatype(Datatype datatype)539 Status check_template_type_to_datatype<uint64_t>(Datatype datatype) {
540   if (datatype == Datatype::UINT64)
541     return Status::Ok();
542   return Status::Error(
543       "Template of type uint64_t but datatype is not Datatype::UINT64");
544 }
545 template <>
check_template_type_to_datatype(Datatype datatype)546 Status check_template_type_to_datatype<float>(Datatype datatype) {
547   if (datatype == Datatype::FLOAT32)
548     return Status::Ok();
549   return Status::Error(
550       "Template of type float but datatype is not Datatype::FLOAT32");
551 }
552 template <>
check_template_type_to_datatype(Datatype datatype)553 Status check_template_type_to_datatype<double>(Datatype datatype) {
554   if (datatype == Datatype::FLOAT64)
555     return Status::Ok();
556   return Status::Error(
557       "Template of type double but datatype is not Datatype::FLOAT64");
558 }
559 template <>
check_template_type_to_datatype(Datatype datatype)560 Status check_template_type_to_datatype<char>(Datatype datatype) {
561   if (datatype == Datatype::CHAR)
562     return Status::Ok();
563   return Status::Error(
564       "Template of type char but datatype is not Datatype::CHAR");
565 }
566 
567 }  // namespace datatype
568 
569 /* ********************************* */
570 /*        GEOMETRY FUNCTIONS         */
571 /* ********************************* */
572 
573 namespace geometry {
574 
575 template <class T>
coords_in_rect(const T * coords,const std::vector<const T * > & rect,unsigned int dim_num)576 inline bool coords_in_rect(
577     const T* coords, const std::vector<const T*>& rect, unsigned int dim_num) {
578   for (unsigned int i = 0; i < dim_num; ++i) {
579     if (coords[i] < rect[i][0] || coords[i] > rect[i][1])
580       return false;
581   }
582 
583   return true;
584 }
585 
586 template <class T>
coords_in_rect(const T * coords,const T * rect,unsigned int dim_num)587 inline bool coords_in_rect(
588     const T* coords, const T* rect, unsigned int dim_num) {
589   for (unsigned int i = 0; i < dim_num; ++i) {
590     if (coords[i] < rect[2 * i] || coords[i] > rect[2 * i + 1])
591       return false;
592   }
593 
594   return true;
595 }
596 
597 template <class T>
overlap(const T * a,const T * b,unsigned dim_num)598 bool overlap(const T* a, const T* b, unsigned dim_num) {
599   for (unsigned i = 0; i < dim_num; ++i) {
600     if (a[2 * i] > b[2 * i + 1] || a[2 * i + 1] < b[2 * i])
601       return false;
602   }
603 
604   return true;
605 }
606 
607 template <class T>
overlap(const T * a,const T * b,unsigned dim_num,T * o,bool * overlap)608 void overlap(const T* a, const T* b, unsigned dim_num, T* o, bool* overlap) {
609   // Get overlap range
610   *overlap = true;
611   for (unsigned int i = 0; i < dim_num; ++i) {
612     o[2 * i] = std::max(a[2 * i], b[2 * i]);
613     o[2 * i + 1] = std::min(a[2 * i + 1], b[2 * i + 1]);
614     if (o[2 * i] > b[2 * i + 1] || o[2 * i + 1] < b[2 * i]) {
615       *overlap = false;
616       break;
617     }
618   }
619 }
620 
621 template <class T>
coverage(const T * a,const T * b,unsigned dim_num)622 double coverage(const T* a, const T* b, unsigned dim_num) {
623   double c = 1.0;
624   auto add = int(std::is_integral<T>::value);
625 
626   for (unsigned i = 0; i < dim_num; ++i) {
627     if (b[2 * i] == b[2 * i + 1]) {
628       c *= 1;
629     } else {
630       auto a_range = double(a[2 * i + 1]) - a[2 * i] + add;
631       auto b_range = double(b[2 * i + 1]) - b[2 * i] + add;
632       if (std::is_integral<T>::value) {
633         auto max = std::numeric_limits<T>::max();
634         if (a_range == 0)
635           a_range = std::nextafter(a_range, max);
636         if (b_range == 0)
637           b_range = std::nextafter(b_range, max);
638       }
639       c *= a_range / b_range;
640     }
641   }
642   return c;
643 }
644 
645 template <class T>
intersection(const std::vector<std::array<T,2>> & r1,const std::vector<std::array<T,2>> & r2)646 std::vector<std::array<T, 2>> intersection(
647     const std::vector<std::array<T, 2>>& r1,
648     const std::vector<std::array<T, 2>>& r2) {
649   auto dim_num = r1.size();
650   assert(r2.size() == dim_num);
651 
652   std::vector<std::array<T, 2>> ret(dim_num);
653   for (size_t d = 0; d < dim_num; ++d)
654     ret[d] = {std::max(r1[d][0], r2[d][0]), std::min(r1[d][1], r2[d][1])};
655 
656   return ret;
657 }
658 
659 }  // namespace geometry
660 
661 /* ********************************* */
662 /*          TIME FUNCTIONS           */
663 /* ********************************* */
664 
665 namespace time {
666 
timestamp_now_ms()667 uint64_t timestamp_now_ms() {
668 #ifdef _WIN32
669   struct _timeb tb;
670   memset(&tb, 0, sizeof(struct _timeb));
671   _ftime_s(&tb);
672   return static_cast<uint64_t>(tb.time * 1000L + tb.millitm);
673 #else
674   struct timeval tp;
675   memset(&tp, 0, sizeof(struct timeval));
676   gettimeofday(&tp, nullptr);
677   return static_cast<uint64_t>(tp.tv_sec * 1000L + tp.tv_usec / 1000);
678 #endif
679 }
680 
681 }  // namespace time
682 
683 /* ********************************* */
684 /*          MATH FUNCTIONS           */
685 /* ********************************* */
686 
687 namespace math {
688 
ceil(uint64_t x,uint64_t y)689 uint64_t ceil(uint64_t x, uint64_t y) {
690   if (y == 0)
691     return 0;
692 
693   return x / y + (x % y != 0);
694 }
695 
log(double b,double x)696 double log(double b, double x) {
697   return ::log(x) / ::log(b);
698 }
699 
700 template <class T>
safe_mul(T a,T b)701 T safe_mul(T a, T b) {
702   T prod = a * b;
703 
704   // Check for overflow only for integers
705   if (std::is_integral<T>::value) {
706     if (prod / a != b)  // Overflow
707       return std::numeric_limits<T>::max();
708   }
709 
710   return prod;
711 }
712 
left_p2_m1(uint64_t value)713 uint64_t left_p2_m1(uint64_t value) {
714   // Edge case
715   if (value == UINT64_MAX)
716     return value;
717 
718   uint64_t ret = 0;  // Min power of 2 minus 1
719   while (ret <= value) {
720     ret = (ret << 1) | 1;  // Next larger power of 2 minus 1
721   }
722 
723   return ret >> 1;
724 }
725 
right_p2_m1(uint64_t value)726 uint64_t right_p2_m1(uint64_t value) {
727   // Edge case
728   if (value == 0)
729     return value;
730 
731   uint64_t ret = UINT64_MAX;  // Max power of 2 minus 1
732   while (ret >= value) {
733     ret >>= 1;  // Next smaller power of 2 minus 1
734   }
735 
736   return (ret << 1) | 1;
737 }
738 
739 }  // namespace math
740 
741 // Explicit template instantiations
742 
743 namespace geometry {
744 
745 template bool coords_in_rect<int>(
746     const int* corrds, const int* subarray, unsigned int dim_num);
747 template bool coords_in_rect<int64_t>(
748     const int64_t* corrds, const int64_t* subarray, unsigned int dim_num);
749 template bool coords_in_rect<float>(
750     const float* coords, const float* subarray, unsigned int dim_num);
751 template bool coords_in_rect<double>(
752     const double* coords, const double* subarray, unsigned int dim_num);
753 template bool coords_in_rect<int8_t>(
754     const int8_t* coords, const int8_t* subarray, unsigned int dim_num);
755 template bool coords_in_rect<uint8_t>(
756     const uint8_t* coords, const uint8_t* subarray, unsigned int dim_num);
757 template bool coords_in_rect<int16_t>(
758     const int16_t* coords, const int16_t* subarray, unsigned int dim_num);
759 template bool coords_in_rect<uint16_t>(
760     const uint16_t* coords, const uint16_t* subarray, unsigned int dim_num);
761 template bool coords_in_rect<uint32_t>(
762     const uint32_t* coords, const uint32_t* subarray, unsigned int dim_num);
763 template bool coords_in_rect<uint64_t>(
764     const uint64_t* coords, const uint64_t* subarray, unsigned int dim_num);
765 
766 template bool coords_in_rect<int>(
767     const int* corrds,
768     const std::vector<const int*>& subarray,
769     unsigned int dim_num);
770 template bool coords_in_rect<int64_t>(
771     const int64_t* corrds,
772     const std::vector<const int64_t*>& subarray,
773     unsigned int dim_num);
774 template bool coords_in_rect<float>(
775     const float* coords,
776     const std::vector<const float*>& subarray,
777     unsigned int dim_num);
778 template bool coords_in_rect<double>(
779     const double* coords,
780     const std::vector<const double*>& subarray,
781     unsigned int dim_num);
782 template bool coords_in_rect<int8_t>(
783     const int8_t* coords,
784     const std::vector<const int8_t*>& subarray,
785     unsigned int dim_num);
786 template bool coords_in_rect<uint8_t>(
787     const uint8_t* coords,
788     const std::vector<const uint8_t*>& subarray,
789     unsigned int dim_num);
790 template bool coords_in_rect<int16_t>(
791     const int16_t* coords,
792     const std::vector<const int16_t*>& subarray,
793     unsigned int dim_num);
794 template bool coords_in_rect<uint16_t>(
795     const uint16_t* coords,
796     const std::vector<const uint16_t*>& subarray,
797     unsigned int dim_num);
798 template bool coords_in_rect<uint32_t>(
799     const uint32_t* coords,
800     const std::vector<const uint32_t*>& subarray,
801     unsigned int dim_num);
802 template bool coords_in_rect<uint64_t>(
803     const uint64_t* coords,
804     const std::vector<const uint64_t*>& subarray,
805     unsigned int dim_num);
806 
807 template bool overlap<int8_t>(
808     const int8_t* a, const int8_t* b, unsigned dim_num);
809 template bool overlap<uint8_t>(
810     const uint8_t* a, const uint8_t* b, unsigned dim_num);
811 template bool overlap<int16_t>(
812     const int16_t* a, const int16_t* b, unsigned dim_num);
813 template bool overlap<uint16_t>(
814     const uint16_t* a, const uint16_t* b, unsigned dim_num);
815 template bool overlap<int>(const int* a, const int* b, unsigned dim_num);
816 template bool overlap<unsigned>(
817     const unsigned* a, const unsigned* b, unsigned dim_num);
818 template bool overlap<int64_t>(
819     const int64_t* a, const int64_t* b, unsigned dim_num);
820 template bool overlap<uint64_t>(
821     const uint64_t* a, const uint64_t* b, unsigned dim_num);
822 template bool overlap<float>(const float* a, const float* b, unsigned dim_num);
823 template bool overlap<double>(
824     const double* a, const double* b, unsigned dim_num);
825 
826 template void overlap<int>(
827     const int* a, const int* b, unsigned dim_num, int* o, bool* overlap);
828 template void overlap<int64_t>(
829     const int64_t* a,
830     const int64_t* b,
831     unsigned dim_num,
832     int64_t* o,
833     bool* overlap);
834 template void overlap<float>(
835     const float* a, const float* b, unsigned dim_num, float* o, bool* overlap);
836 template void overlap<double>(
837     const double* a,
838     const double* b,
839     unsigned dim_num,
840     double* o,
841     bool* overlap);
842 template void overlap<int8_t>(
843     const int8_t* a,
844     const int8_t* b,
845     unsigned dim_num,
846     int8_t* o,
847     bool* overlap);
848 template void overlap<uint8_t>(
849     const uint8_t* a,
850     const uint8_t* b,
851     unsigned dim_num,
852     uint8_t* o,
853     bool* overlap);
854 template void overlap<int16_t>(
855     const int16_t* a,
856     const int16_t* b,
857     unsigned dim_num,
858     int16_t* o,
859     bool* overlap);
860 template void overlap<uint16_t>(
861     const uint16_t* a,
862     const uint16_t* b,
863     unsigned dim_num,
864     uint16_t* o,
865     bool* overlap);
866 template void overlap<uint32_t>(
867     const uint32_t* a,
868     const uint32_t* b,
869     unsigned dim_num,
870     uint32_t* o,
871     bool* overlap);
872 template void overlap<uint64_t>(
873     const uint64_t* a,
874     const uint64_t* b,
875     unsigned dim_num,
876     uint64_t* o,
877     bool* overlap);
878 
879 template double coverage<int8_t>(
880     const int8_t* a, const int8_t* b, unsigned dim_num);
881 template double coverage<uint8_t>(
882     const uint8_t* a, const uint8_t* b, unsigned dim_num);
883 template double coverage<int16_t>(
884     const int16_t* a, const int16_t* b, unsigned dim_num);
885 template double coverage<uint16_t>(
886     const uint16_t* a, const uint16_t* b, unsigned dim_num);
887 template double coverage<int>(const int* a, const int* b, unsigned dim_num);
888 template double coverage<unsigned>(
889     const unsigned* a, const unsigned* b, unsigned dim_num);
890 template double coverage<int64_t>(
891     const int64_t* a, const int64_t* b, unsigned dim_num);
892 template double coverage<uint64_t>(
893     const uint64_t* a, const uint64_t* b, unsigned dim_num);
894 template double coverage<float>(
895     const float* a, const float* b, unsigned dim_num);
896 template double coverage<double>(
897     const double* a, const double* b, unsigned dim_num);
898 
899 template std::vector<std::array<int8_t, 2>> intersection<int8_t>(
900     const std::vector<std::array<int8_t, 2>>& r1,
901     const std::vector<std::array<int8_t, 2>>& r2);
902 template std::vector<std::array<uint8_t, 2>> intersection<uint8_t>(
903     const std::vector<std::array<uint8_t, 2>>& r1,
904     const std::vector<std::array<uint8_t, 2>>& r2);
905 template std::vector<std::array<int16_t, 2>> intersection<int16_t>(
906     const std::vector<std::array<int16_t, 2>>& r1,
907     const std::vector<std::array<int16_t, 2>>& r2);
908 template std::vector<std::array<uint16_t, 2>> intersection<uint16_t>(
909     const std::vector<std::array<uint16_t, 2>>& r1,
910     const std::vector<std::array<uint16_t, 2>>& r2);
911 template std::vector<std::array<int32_t, 2>> intersection<int32_t>(
912     const std::vector<std::array<int32_t, 2>>& r1,
913     const std::vector<std::array<int32_t, 2>>& r2);
914 template std::vector<std::array<uint32_t, 2>> intersection<uint32_t>(
915     const std::vector<std::array<uint32_t, 2>>& r1,
916     const std::vector<std::array<uint32_t, 2>>& r2);
917 template std::vector<std::array<int64_t, 2>> intersection<int64_t>(
918     const std::vector<std::array<int64_t, 2>>& r1,
919     const std::vector<std::array<int64_t, 2>>& r2);
920 template std::vector<std::array<uint64_t, 2>> intersection<uint64_t>(
921     const std::vector<std::array<uint64_t, 2>>& r1,
922     const std::vector<std::array<uint64_t, 2>>& r2);
923 
924 }  // namespace geometry
925 
926 namespace math {
927 
928 template int8_t safe_mul<int8_t>(int8_t a, int8_t b);
929 template uint8_t safe_mul<uint8_t>(uint8_t a, uint8_t b);
930 template int16_t safe_mul<int16_t>(int16_t a, int16_t b);
931 template uint16_t safe_mul<uint16_t>(uint16_t a, uint16_t b);
932 template int32_t safe_mul<int32_t>(int32_t a, int32_t b);
933 template uint32_t safe_mul<uint32_t>(uint32_t a, uint32_t b);
934 template int64_t safe_mul<int64_t>(int64_t a, int64_t b);
935 template uint64_t safe_mul<uint64_t>(uint64_t a, uint64_t b);
936 template float safe_mul<float>(float a, float b);
937 template double safe_mul<double>(double a, double b);
938 
939 }  // namespace math
940 
941 namespace parse {
942 
943 template std::string to_str<int32_t>(const int32_t& value);
944 template std::string to_str<uint32_t>(const uint32_t& value);
945 
946 }  // namespace parse
947 
948 }  // namespace utils
949 
950 }  // namespace sm
951 }  // namespace tiledb
952