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