1 // Copyright (c) Lawrence Livermore National Security, LLC and other Conduit 2 // Project developers. See top-level LICENSE AND COPYRIGHT files for dates and 3 // other details. No copyright assignment is required to contribute to Conduit. 4 5 //----------------------------------------------------------------------------- 6 /// 7 /// file: conduit_utils.hpp 8 /// 9 //----------------------------------------------------------------------------- 10 11 #ifndef CONDUIT_UTILS_HPP 12 #define CONDUIT_UTILS_HPP 13 14 //----------------------------------------------------------------------------- 15 // -- standard lib includes -- 16 //----------------------------------------------------------------------------- 17 #include <string> 18 #include <vector> 19 #include <iostream> 20 #include <iomanip> 21 #include <sstream> 22 23 24 //----------------------------------------------------------------------------- 25 // -- conduit includes -- 26 //----------------------------------------------------------------------------- 27 #include "conduit_core.hpp" 28 29 //----------------------------------------------------------------------------- 30 // 31 /// The CONDUIT_INFO macro is the primary mechanism used to log basic messages. 32 /// It calls conduit::utils::handle_info() which invokes 33 /// 34 /// The default info handler prints the message to std::out. 35 /// You can change the info handler via conduit::utils::set_info_handler(). 36 /// 37 //----------------------------------------------------------------------------- 38 #define CONDUIT_INFO( msg ) \ 39 { \ 40 std::ostringstream conduit_oss_info; \ 41 conduit_oss_info << msg; \ 42 conduit::utils::handle_info( conduit_oss_info.str(), \ 43 std::string(__FILE__), \ 44 __LINE__); \ 45 } \ 46 47 //----------------------------------------------------------------------------- 48 // 49 /// The CONDUIT_WARN macro is the primary mechanism used to capture warnings 50 /// in conduit. It calls conduit::utils::handle_warning() which invokes 51 /// the currently configured warning handler. 52 /// 53 /// The default warning handler throws a c++ exception, in the form of a 54 /// conduit::Error instance. You can change the error handler via 55 /// conduit::utils::set_warning_handler(). 56 // 57 //----------------------------------------------------------------------------- 58 #define CONDUIT_WARN( msg ) \ 59 { \ 60 std::ostringstream conduit_oss_warn; \ 61 conduit_oss_warn << msg; \ 62 conduit::utils::handle_warning( conduit_oss_warn.str(), \ 63 std::string(__FILE__), \ 64 __LINE__); \ 65 } \ 66 67 //----------------------------------------------------------------------------- 68 // 69 /// The CONDUIT_ERROR macro is the primary mechanism used to capture errors 70 /// in conduit. It calls conduit::utils::handle_error() which invokes 71 /// the currently configured error handler. 72 /// 73 /// The default error handler throws a c++ exception, in the form of a 74 /// conduit::Error instance. You can change the error handler via 75 /// conduit::utils::set_error_handler(). 76 // 77 //----------------------------------------------------------------------------- 78 #define CONDUIT_ERROR( msg ) \ 79 { \ 80 std::ostringstream conduit_oss_error; \ 81 conduit_oss_error << msg; \ 82 conduit::utils::handle_error( conduit_oss_error.str(), \ 83 std::string(__FILE__), \ 84 __LINE__); \ 85 } \ 86 87 //----------------------------------------------------------------------------- 88 // 89 /// The CONDUIT_ASSERT macro is the primary mechanism used to for asserts 90 /// in conduit. It calls conduit::utils::handle_error() which invokes 91 /// the currently configured error handler. 92 /// 93 /// The default error handler throws a c++ exception, in the form of a 94 /// conduit::Error instance. You can change the error handler via 95 /// conduit::utils::set_error_handler(). 96 // 97 //----------------------------------------------------------------------------- 98 #define CONDUIT_ASSERT( cond, msg ) \ 99 { \ 100 if(!cond) \ 101 { \ 102 std::ostringstream conduit_oss_assert; \ 103 conduit_oss_assert << msg; \ 104 conduit::utils::handle_error( conduit_oss_assert.str(), \ 105 std::string(__FILE__), \ 106 __LINE__); \ 107 } \ 108 } \ 109 110 //----------------------------------------------------------------------------- 111 // 112 /// The CONDUIT_CHECK macro is the mechanism used for checks in conduit. 113 /// It calls conduit::utils::handle_warning() which invokes 114 /// the currently configured warning handler. 115 /// 116 /// The default warning handler throws a c++ exception, in the form of a 117 /// conduit::Error instance. You can change the error handler via 118 /// conduit::utils::set_warning_handler(). 119 // 120 //----------------------------------------------------------------------------- 121 #define CONDUIT_CHECK( cond, msg ) \ 122 { \ 123 if(!cond) \ 124 { \ 125 std::ostringstream conduit_oss_check; \ 126 conduit_oss_check << msg; \ 127 conduit::utils::handle_warning( conduit_oss_check.str(), \ 128 std::string(__FILE__), \ 129 __LINE__); \ 130 } \ 131 } \ 132 133 //----------------------------------------------------------------------------- 134 // 135 /// The CONDUIT_EPSILON macro defines the default machine epsilon 136 /// value used when comparing floating-point values. This value is used 137 /// by default in all of the Conduit comparison operations (e.g. 138 /// 'conduit::Node::diff' and 'conduit::Node::diff_compatible'). 139 // 140 //----------------------------------------------------------------------------- 141 #define CONDUIT_EPSILON 1e-12 142 143 144 //----------------------------------------------------------------------------- 145 // 146 /// The CONDUIT_UNUSED macro is used to identify unused variables 147 /// in cases where it is difficult to avoid defining in the method signature 148 /// for methods that use optional features. 149 /// 150 //----------------------------------------------------------------------------- 151 #define CONDUIT_UNUSED( var ) (void)(var) 152 153 //----------------------------------------------------------------------------- 154 // -- begin conduit:: -- 155 //----------------------------------------------------------------------------- 156 namespace conduit 157 { 158 159 // fwd declare Node 160 class Node; 161 162 //----------------------------------------------------------------------------- 163 // -- begin conduit::utils -- 164 //----------------------------------------------------------------------------- 165 namespace utils 166 { 167 //----------------------------------------------------------------------------- 168 /// Primary interface used by the conduit API when an info message is issued 169 /// This simply dispatches the message to the currently configured info handler. 170 /// The default info handler prints a the message to std::cout; 171 //----------------------------------------------------------------------------- 172 void CONDUIT_API handle_info(const std::string &msg, 173 const std::string &file, 174 int line); 175 176 //----------------------------------------------------------------------------- 177 /// Info handler callback function type 178 //----------------------------------------------------------------------------- 179 typedef void(*conduit_info_handler)(const std::string &, 180 const std::string &, 181 int); 182 183 //----------------------------------------------------------------------------- 184 /// Default info message handler, which prints the message to std::cout; 185 //----------------------------------------------------------------------------- 186 void CONDUIT_API default_info_handler(const std::string &msg, 187 const std::string &file, 188 int line); 189 190 //----------------------------------------------------------------------------- 191 /// Allows other libraries to provide an alternate info message handler. 192 //----------------------------------------------------------------------------- 193 void CONDUIT_API set_info_handler(conduit_info_handler on_info); 194 195 //----------------------------------------------------------------------------- 196 /// Returns the active info message handler. 197 //----------------------------------------------------------------------------- 198 conduit_info_handler CONDUIT_API info_handler(); 199 200 //----------------------------------------------------------------------------- 201 /// Primary interface used by the conduit API when a warning is issued. 202 /// This simply dispatches the warning to the currently configured warning handler. 203 /// The default warning handler throws a conduit::Error exception. 204 //----------------------------------------------------------------------------- 205 void CONDUIT_API handle_warning(const std::string &msg, 206 const std::string &file, 207 int line); 208 209 //----------------------------------------------------------------------------- 210 /// Warning handler callback function type 211 //----------------------------------------------------------------------------- 212 typedef void(*conduit_warning_handler)(const std::string &, 213 const std::string &, 214 int); 215 216 //----------------------------------------------------------------------------- 217 /// Default warning handler, which throws a conduit::Error exception. 218 //----------------------------------------------------------------------------- 219 void CONDUIT_API default_warning_handler(const std::string &msg, 220 const std::string &file, 221 int line); 222 223 //----------------------------------------------------------------------------- 224 /// Allows other libraries to provide an alternate warning handler. 225 //----------------------------------------------------------------------------- 226 void CONDUIT_API set_warning_handler(conduit_warning_handler on_warning); 227 228 //----------------------------------------------------------------------------- 229 /// Returns the active warning message handler. 230 //----------------------------------------------------------------------------- 231 conduit_warning_handler CONDUIT_API warning_handler(); 232 233 //----------------------------------------------------------------------------- 234 /// Primary interface used by the conduit API when an error occurs. 235 /// This simply dispatches the error to the currently configured error handler. 236 /// The default error handler throws a conduit::Error exception. 237 //----------------------------------------------------------------------------- 238 void CONDUIT_API handle_error(const std::string &msg, 239 const std::string &file, 240 int line); 241 242 //----------------------------------------------------------------------------- 243 /// Default error handler, which throws a conduit::Error exception. 244 //----------------------------------------------------------------------------- 245 void CONDUIT_API default_error_handler(const std::string &msg, 246 const std::string &file, 247 int line); 248 //----------------------------------------------------------------------------- 249 /// Warning handler callback function type 250 //----------------------------------------------------------------------------- 251 typedef void(*conduit_error_handler)(const std::string &, 252 const std::string &, 253 int); 254 255 //----------------------------------------------------------------------------- 256 /// Allows other libraries to provide an alternate error handler. 257 //----------------------------------------------------------------------------- 258 void CONDUIT_API set_error_handler(conduit_error_handler on_error); 259 260 //----------------------------------------------------------------------------- 261 /// Returns the active warning message handler. 262 //----------------------------------------------------------------------------- 263 conduit_error_handler CONDUIT_API error_handler(); 264 265 266 267 //----------------------------------------------------------------------------- 268 /// Primary interface used by the conduit API to move memory. 269 //----------------------------------------------------------------------------- 270 271 // conduit uses a single pair of memset and memcpy functions to 272 // manage data movement. 273 274 // this strategy allows downstream users to support complex cases 275 // like moving between memory spaces not accessible on the host. 276 // 277 // These methods aren't bound to allocators b/c allocators 278 // won't be tied into all of the places where source and dest pointers 279 // need to be located. 280 // 281 void CONDUIT_API set_memcpy_handler(void(*conduit_hnd_copy)(void*, 282 const void *, 283 size_t)); 284 void CONDUIT_API set_memset_handler(void(*conduit_hnd_memset)(void*, 285 int, 286 size_t)); 287 288 void CONDUIT_API default_memset_handler(void *ptr, 289 int value, 290 size_t num); 291 292 void CONDUIT_API default_memcpy_handler(void *destination, 293 const void *source, 294 size_t num); 295 296 // general memcpy interface used by conduit 297 void CONDUIT_API conduit_memcpy(void *destination, 298 const void *source, 299 size_t num); 300 301 void CONDUIT_API conduit_memcpy_strided_elements(void *dest, 302 size_t num_elements, 303 size_t ele_bytes, 304 size_t dest_stride, 305 const void *src, 306 size_t src_stride); 307 308 // general memset interface used by conduit 309 // NOTE (cyrush): The default memset returns the orig pointer, but 310 // other allocators like cuda do not. 311 // TODO: GIVEN THIS DO WE NEED TO PASS AN ALLOC_ID? 312 void CONDUIT_API conduit_memset(void * ptr, 313 int value, 314 size_t num); 315 316 //----------------------------------------------------------------------------- 317 /// Primary interface used by the conduit API to allocate memory. 318 //----------------------------------------------------------------------------- 319 320 // register a custom allocator 321 index_t CONDUIT_API register_allocator(void*(*conduit_hnd_allocate) (size_t, size_t), 322 void(*conduit_hnd_free)(void *)); 323 324 // generic allocate interface 325 // allocator_id 0 is the default 326 void CONDUIT_API * conduit_allocate(size_t num_items, 327 size_t item_size, 328 index_t allocator_id = 0); 329 330 // generic free interface 331 void CONDUIT_API conduit_free(void *data_ptr, 332 index_t allocator_id = 0); 333 334 335 336 //----------------------------------------------------------------------------- 337 /// Helpers for common string splitting operations. 338 //----------------------------------------------------------------------------- 339 void CONDUIT_API split_string(const std::string &str, 340 const std::string &sep, 341 std::string &curr, 342 std::string &next); 343 344 void CONDUIT_API split_string(const std::string &str, 345 char sep, 346 std::vector<std::string> &sv); 347 348 void CONDUIT_API rsplit_string(const std::string &str, 349 const std::string &sep, 350 std::string &curr, 351 std::string &next); 352 353 //------------------------------------------------------------------------ 354 /// Removes the the leading and trailing whitespace from the string 'str'. 355 /// 'chars_to_trim' can be overriden to trim a different set of characters 356 /// from 'str'. 357 //------------------------------------------------------------------------- 358 void CONDUIT_API trim_string(std::string &str, 359 const char *chars_to_trim = " \t\n\r\f\v"); 360 361 //----------------------------------------------------------------------------- 362 /// Helpers for splitting and joining conduit paths (which always use "/") 363 //----------------------------------------------------------------------------- 364 void CONDUIT_API split_path(const std::string &path, 365 std::string &curr, 366 std::string &next); 367 368 void CONDUIT_API rsplit_path(const std::string &path, 369 std::string &curr, 370 std::string &next); 371 372 std::string CONDUIT_API join_path(const std::string &left, 373 const std::string &right); 374 375 //----------------------------------------------------------------------------- 376 /// Helpers for splitting and joining file system paths. 377 /// These use the proper platform specific separator (/ or \). 378 //----------------------------------------------------------------------------- 379 std::string CONDUIT_API file_path_separator(); 380 381 void CONDUIT_API split_file_path(const std::string &path, 382 std::string &curr, 383 std::string &next); 384 385 void CONDUIT_API rsplit_file_path(const std::string &path, 386 std::string &curr, 387 std::string &next); 388 389 //------------------------------------------------------------------------ 390 /// `split_file_path` and `rsplit_file_path` are helpers that allows us to 391 /// use ":" for subpaths even on Windows when a drive letter including 392 /// ":" is in the path. 393 //------------------------------------------------------------------------- 394 void CONDUIT_API split_file_path(const std::string &str, 395 const std::string &sep, 396 std::string &curr, 397 std::string &next); 398 399 void CONDUIT_API rsplit_file_path(const std::string &str, 400 const std::string &sep, 401 std::string &curr, 402 std::string &next); 403 404 405 std::string CONDUIT_API join_file_path(const std::string &left, 406 const std::string &right); 407 408 409 410 411 //----------------------------------------------------------------------------- 412 bool CONDUIT_API is_file(const std::string &path); 413 414 //----------------------------------------------------------------------------- 415 bool CONDUIT_API is_directory(const std::string &path); 416 417 //----------------------------------------------------------------------------- 418 /// Lists the items contained in the given directory. 419 /// Each entry returned in "contents" will have the directory 420 /// included in the path. 421 /// 422 /// Queries the system for the contents of the given directory. 423 /// Does not perform any checks on the returned filenames, could be 424 /// directories or files (anything a directory may contain). 425 /// 426 /// Param "directory" must be the path to a directory. 427 /// Param "ignore_dot" ignores any items starting with '.' 428 /// (ie: "." or ".." or ".dotfile"), defaulted to true. 429 /// returns false if there was an error opening the provided directory, 430 /// true otherwise. 431 //----------------------------------------------------------------------------- 432 bool CONDUIT_API list_directory_contents(const std::string &directory, 433 std::vector<std::string> &contents, 434 bool ignore_dot = true); 435 436 //----------------------------------------------------------------------------- 437 index_t CONDUIT_API file_size(const std::string &path); 438 439 //----------------------------------------------------------------------------- 440 /// Creates a new directory. 441 /// 442 /// Does not recursively create parent directories if they do not already 443 /// exist. 444 //----------------------------------------------------------------------------- 445 bool CONDUIT_API create_directory(const std::string &path); 446 447 //----------------------------------------------------------------------------- 448 /// Remove files, or empty directories 449 //----------------------------------------------------------------------------- 450 bool CONDUIT_API remove_file(const std::string &path); 451 452 bool CONDUIT_API remove_directory(const std::string &path); 453 454 bool CONDUIT_API remove_path_if_exists(const std::string &path); 455 456 //----------------------------------------------------------------------------- 457 int CONDUIT_API system_execute(const std::string &cmd); 458 459 460 //----------------------------------------------------------------------------- 461 /// Helpers for escaping / unescaping special characters in strings. 462 /// 463 /// Our main use case for escaping is json, so we support the escape rules 464 /// outlined by the json standard (see: http://www.json.org/). 465 /// 466 /// List of supported special characters. 467 /// " (quote) 468 /// \ (backward slash) 469 /// \n (newline) 470 /// \t (tab) 471 /// \b (backspace) 472 /// \f (form feed) 473 /// \r (carriage return) 474 /// 475 /// Special chars that are not escaped, but are unescaped: 476 /// / (forward slash) 477 /// 478 /// Special chars that are not escaped or unescaped: 479 /// \u (for hex escapes: \uFFFF) 480 /// 481 //----------------------------------------------------------------------------- 482 std::string CONDUIT_API escape_special_chars(const std::string &input); 483 std::string CONDUIT_API unescape_special_chars(const std::string &input); 484 485 486 //----------------------------------------------------------------------------- 487 /// fmt style string formatting helpers 488 //----------------------------------------------------------------------------- 489 490 std::string CONDUIT_API format(const std::string &s, 491 const conduit::Node &args); 492 493 std::string CONDUIT_API format(const std::string &s, 494 const conduit::Node &maps, 495 index_t map_index); 496 497 //----------------------------------------------------------------------------- 498 /// Base64 Encoding of Buffers 499 //----------------------------------------------------------------------------- 500 void CONDUIT_API base64_encode(const void *src, 501 index_t src_nbytes, 502 void *dest); 503 504 index_t CONDUIT_API base64_encode_buffer_size(index_t src_nbytes); 505 506 index_t CONDUIT_API base64_decode_buffer_size(index_t encoded_nbytes); 507 508 509 void CONDUIT_API base64_decode(const void *src, 510 index_t src_nbytes, 511 void *dest); 512 513 //----------------------------------------------------------------------------- 514 std::string CONDUIT_API json_sanitize(const std::string &json); 515 516 //----------------------------------------------------------------------------- 517 // declare then define to avoid icc warnings 518 template< typename T > 519 std::string to_hex_string(T value); 520 521 template< typename T > to_hex_string(T value)522 std::string to_hex_string(T value) 523 { 524 std::stringstream oss; 525 oss << std::hex << value; 526 return oss.str(); 527 } 528 529 //----------------------------------------------------------------------------- 530 // Helpers to identify value cast consequences 531 //----------------------------------------------------------------------------- 532 // adapted from: https://stackoverflow.com/a/17225324/203071 533 template< typename T_SRC, typename T_DEST> value_fits(T_SRC value)534 bool value_fits(T_SRC value) 535 { 536 if(std::is_same<T_SRC,T_DEST>()) 537 { 538 return true; 539 } 540 541 return ( (value > static_cast<T_SRC>(0) ) == 542 (static_cast<T_DEST>(value) > static_cast<T_DEST>(0)) 543 ) && static_cast<T_SRC>(static_cast<T_DEST>(value)) == value; 544 545 } 546 547 548 549 550 //----------------------------------------------------------------------------- 551 // Helpers to identify if a string contains an integer. 552 //----------------------------------------------------------------------------- 553 bool CONDUIT_API string_is_integer(const std::string &s); 554 555 //----------------------------------------------------------------------------- 556 // Helper that wraps parsing a string value into another type. 557 //----------------------------------------------------------------------------- 558 // declare then define to avoid icc warnings 559 template< typename T > 560 T string_to_value(const std::string &s); 561 562 template< typename T > string_to_value(const std::string & s)563 T string_to_value(const std::string &s) 564 { 565 T res; 566 std::istringstream iss(s); 567 iss >> res; 568 return res; 569 } 570 571 572 //----------------------------------------------------------------------------- 573 // floating point to string helper, strikes a balance of what we want 574 // for format-wise for debug printing and json + yaml. 575 //----------------------------------------------------------------------------- 576 std::string CONDUIT_API float64_to_string(float64 value); 577 578 //----------------------------------------------------------------------------- 579 void CONDUIT_API indent(std::ostream &os, 580 index_t indent, 581 index_t depth, 582 const std::string &pad); 583 584 //----------------------------------------------------------------------------- 585 void CONDUIT_API sleep(index_t milliseconds); 586 587 //----------------------------------------------------------------------------- 588 // String hash functions 589 //----------------------------------------------------------------------------- 590 unsigned int CONDUIT_API hash(const char *k, 591 unsigned int length, 592 unsigned int initval = 0); 593 unsigned int CONDUIT_API hash(const char *k, 594 unsigned int initval = 0); 595 unsigned int CONDUIT_API hash(const std::string &k, 596 unsigned int initval = 0); 597 598 } 599 //----------------------------------------------------------------------------- 600 // -- end conduit::utils -- 601 //----------------------------------------------------------------------------- 602 603 } 604 //----------------------------------------------------------------------------- 605 // -- end conduit:: -- 606 //----------------------------------------------------------------------------- 607 608 #endif 609