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*)×tamp_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*)×tamp_range->first,
265 (long long int*)×tamp_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