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_relay_io_handle.cpp
8 ///
9 //-----------------------------------------------------------------------------
10 
11 #ifdef CONDUIT_RELAY_IO_MPI_ENABLED
12     // FIXME:
13     #include "conduit_relay_io_handle.hpp"
14 #else
15     #include "conduit_relay_io_handle.hpp"
16 #endif
17 
18 #include "conduit_relay_io.hpp"
19 
20 #include "conduit_relay_io_handle_sidre.hpp"
21 
22 #ifdef CONDUIT_RELAY_IO_HDF5_ENABLED
23     #include "conduit_relay_io_hdf5.hpp"
24 #endif
25 
26 
27 //-----------------------------------------------------------------------------
28 // standard lib includes
29 //-----------------------------------------------------------------------------
30 
31 //-----------------------------------------------------------------------------
32 // -- begin conduit:: --
33 //-----------------------------------------------------------------------------
34 namespace conduit
35 {
36 
37 //-----------------------------------------------------------------------------
38 // -- begin conduit::relay --
39 //-----------------------------------------------------------------------------
40 namespace relay
41 {
42 
43 #ifdef CONDUIT_RELAY_IO_MPI_ENABLED
44 //-----------------------------------------------------------------------------
45 // -- begin conduit::relay::mpi --
46 //-----------------------------------------------------------------------------
47 namespace mpi
48 {
49 #endif
50 
51 //-----------------------------------------------------------------------------
52 // -- begin conduit::relay::<mpi>::io --
53 //-----------------------------------------------------------------------------
54 namespace io
55 {
56 
57 
58 
59 
60 
61 //-----------------------------------------------------------------------------
62 // BasicHandle -- IO Handle implementation for built-in protocols
63 //-----------------------------------------------------------------------------
64 class BasicHandle: public IOHandle::HandleInterface
65 {
66 public:
67     BasicHandle(const std::string &path,
68                 const std::string &protocol,
69                 const Node &options);
70     virtual ~BasicHandle();
71 
72     void open();
73 
74     bool is_open() const;
75 
76     // main interface methods
77     void read(Node &node);
78     void read(Node &node, const Node &opts);
79     void read(const std::string &path,
80               Node &node);
81     void read(const std::string &path,
82               Node &node,
83               const Node &opts);
84 
85     void write(const Node &node);
86     void write(const Node &node, const Node &opts);
87     void write(const Node &node,
88                const std::string &path);
89     void write(const Node &node,
90                const std::string &path,
91                const Node &opts);
92 
93     void remove(const std::string &path);
94 
95     void list_child_names(std::vector<std::string> &res);
96     void list_child_names(const std::string &path,
97                           std::vector<std::string> &res);
98 
99     bool has_path(const std::string &path);
100 
101     void close();
102 
103 private:
104     Node m_node;
105     bool m_open;
106 
107 };
108 
109 
110 //-----------------------------------------------------------------------------
111 // HDF5Handle -- IO Handle implementation for HDF5
112 //-----------------------------------------------------------------------------
113 #ifdef CONDUIT_RELAY_IO_HDF5_ENABLED
114 //-----------------------------------------------------------------------------
115 class HDF5Handle: public IOHandle::HandleInterface
116 {
117 public:
118     HDF5Handle(const std::string &path,
119                const std::string &protocol,
120                const Node &options);
121     virtual ~HDF5Handle();
122 
123     void open();
124 
125     bool is_open() const;
126 
127     // main interface methods
128     void read(Node &node);
129     void read(Node &node, const Node &opts);
130     void read(const std::string &path,
131               Node &node);
132     void read(const std::string &path,
133               Node &node,
134               const Node &opts);
135 
136     void write(const Node &node);
137     void write(const Node &node, const Node &opts);
138     void write(const Node &node,
139                const std::string &path);
140     void write(const Node &node,
141                const std::string &path,
142                const Node &opts);
143 
144     void remove(const std::string &path);
145 
146     void list_child_names(std::vector<std::string> &res);
147     void list_child_names(const std::string &path,
148                           std::vector<std::string> &res);
149 
150     bool has_path(const std::string &path);
151 
152     void close();
153 
154 private:
155     hid_t m_h5_id;
156 
157 };
158 //-----------------------------------------------------------------------------
159 #endif
160 //-----------------------------------------------------------------------------
161 
162 
163 //-----------------------------------------------------------------------------
164 // HandleInterface Implementation
165 //-----------------------------------------------------------------------------
166 
167 //-----------------------------------------------------------------------------
HandleInterface(const std::string & path,const std::string & protocol,const Node & options)168 IOHandle::HandleInterface::HandleInterface(const std::string &path,
169                                            const std::string &protocol,
170                                            const Node &options)
171 : m_path(path),
172   m_protocol(protocol),
173   m_options(options)
174 {
175     // empty
176 }
177 
178 //-----------------------------------------------------------------------------
~HandleInterface()179 IOHandle::HandleInterface::~HandleInterface()
180 {
181     // empty
182 }
183 
184 
185 //-----------------------------------------------------------------------------
186 void
open()187 IOHandle::HandleInterface::open()
188 {
189     // checks for subpaths, which we don't currently support
190 
191     std::string file_path;
192     std::string subpath;
193 
194     // check for ":" split
195     conduit::utils::split_file_path(path(),
196                                     std::string(":"),
197                                     file_path,
198                                     subpath);
199     if( !subpath.empty() )
200     {
201         CONDUIT_ERROR("IOHandle does not support opening paths with "
202                       "subpaths specified: \"" << path() << "\"");
203     }
204 
205     m_open_mode = "rwa"; // default to rw, append
206 
207     m_open_mode_read     = true;
208     m_open_mode_write    = true;
209     m_open_mode_append   = true;
210     m_open_mode_truncate = false;
211 
212     // check if options includes open mode
213     if(options().has_child("mode") && options()["mode"].dtype().is_string())
214     {
215         std::string opts_mode = options()["mode"].as_string();
216 
217         m_open_mode = "";
218 
219         m_open_mode_read     = false;
220         m_open_mode_write    = false;
221         m_open_mode_append   = false;
222         m_open_mode_truncate = false;
223 
224         if(opts_mode.find("r") != std::string::npos)
225         {
226             m_open_mode += "r";
227             m_open_mode_read = true;
228         }
229 
230         if(opts_mode.find("w") != std::string::npos)
231         {
232             m_open_mode += "w";
233             m_open_mode_write = true;
234         }
235 
236         // we need at least read or write
237         if(! m_open_mode_read && ! m_open_mode_write)
238         {
239             CONDUIT_ERROR("IOHandle: invalid open mode:"
240                           << "\"" << opts_mode << "\"."
241                           << " 'mode' string must provide"
242                           << " 'r' (read) and/or 'w' (write)."
243                           << " Expected string: {rw}{a|t}");
244         }
245 
246         // note append and truncate are mut-ex.
247         if(opts_mode.find("a") != std::string::npos)
248         {
249             if( opts_mode.find("t") != std::string::npos )
250             {
251                 CONDUIT_ERROR("IOHandle: invalid open mode:"
252                               << "\"" << opts_mode << "\"."
253                               << " In 'mode' string "
254                               << " 'a' (append) and 't' (truncate)"
255                               << " cannot be used together."
256                               << " Expected string: {rw}{a|t}");
257             }
258             m_open_mode += "a";
259             m_open_mode_append = true;
260         }
261 
262         // we checked for both above, so it's safe just check for t here
263         if(opts_mode.find("t") != std::string::npos)
264         {
265             m_open_mode += "t";
266             m_open_mode_truncate = true;
267         }
268 
269         if( !m_open_mode_append && !m_open_mode_truncate)
270         {
271             // if neither append or truncate were specified,
272             // default to append
273             m_open_mode += "a";
274             m_open_mode_append = true;
275         }
276     }
277 }
278 
279 
280 //-----------------------------------------------------------------------------
281 IOHandle::HandleInterface *
create(const std::string & path)282 IOHandle::HandleInterface::create(const std::string &path)
283 {
284     std::string protocol;
285     Node options;
286     return create(path,protocol,options);
287 }
288 
289 //-----------------------------------------------------------------------------
290 IOHandle::HandleInterface *
create(const std::string & path,const std::string & protocol)291 IOHandle::HandleInterface::create(const std::string &path,
292                                   const std::string &protocol)
293 {
294     Node options;
295     return create(path,protocol,options);
296 }
297 
298 //-----------------------------------------------------------------------------
299 IOHandle::HandleInterface *
create(const std::string & path,const Node & options)300 IOHandle::HandleInterface::create(const std::string &path,
301                                   const Node &options)
302 {
303     std::string protocol;
304     return create(path,protocol,options);
305 }
306 
307 //-----------------------------------------------------------------------------
308 IOHandle::HandleInterface *
create(const std::string & path,const std::string & protocol_,const Node & options)309 IOHandle::HandleInterface::create(const std::string &path,
310                                   const std::string &protocol_,
311                                   const Node &options)
312 {
313     HandleInterface *res = NULL;
314     std::string protocol = protocol_;
315 
316     // allow empty protocol to be used for auto detect
317     if(protocol.empty())
318     {
319         conduit::relay::io::identify_protocol(path,protocol);
320     }
321 
322     if(protocol == "conduit_bin" ||
323        protocol == "json" ||
324        protocol == "conduit_json" ||
325        protocol == "conduit_base64_json" ||
326        protocol == "yaml" )
327     {
328         res = new BasicHandle(path, protocol, options);
329     }
330     else if( protocol == "sidre_hdf5" )
331     {
332         // magic interface
333         // path is the path to the root file
334         res = new SidreIOHandle(path,protocol,options);
335     }
336     else if( protocol == "hdf5" )
337     {
338     #ifdef CONDUIT_RELAY_IO_HDF5_ENABLED
339         res = new HDF5Handle(path, protocol, options);
340     #else
341         CONDUIT_ERROR("conduit_relay lacks HDF5 support: " <<
342                       "Cannot create Relay I/O Handle for HDF5" << path);
343     #endif
344     }
345     else
346     {
347         CONDUIT_ERROR("Relay I/O Handle does not support the protocol: "
348                       << protocol);
349     }
350     return res;
351 }
352 
353 //-----------------------------------------------------------------------------
354 const std::string &
path() const355 IOHandle::HandleInterface::path() const
356 {
357     return m_path;
358 }
359 
360 //-----------------------------------------------------------------------------
361 const std::string &
protocol() const362 IOHandle::HandleInterface::protocol() const
363 {
364     return m_protocol;
365 }
366 
367 //-----------------------------------------------------------------------------
368 const std::string &
open_mode() const369 IOHandle::HandleInterface::open_mode() const
370 {
371     return m_open_mode;
372 }
373 
374 //-----------------------------------------------------------------------------
375 const Node &
options() const376 IOHandle::HandleInterface::options() const
377 {
378     return m_options;
379 }
380 
381 
382 //-----------------------------------------------------------------------------
383 // BasicHandle Implementation
384 //-----------------------------------------------------------------------------
BasicHandle(const std::string & path,const std::string & protocol,const Node & options)385 BasicHandle::BasicHandle(const std::string &path,
386                          const std::string &protocol,
387                          const Node &options)
388 : HandleInterface(path,protocol,options),
389   m_node(),
390   m_open(false)
391 {
392     // empty
393 }
394 //-----------------------------------------------------------------------------
~BasicHandle()395 BasicHandle::~BasicHandle()
396 {
397     close();
398 }
399 
400 //-----------------------------------------------------------------------------
401 void
open()402 BasicHandle::open()
403 {
404     close();
405     // call base class method, which does final sanity checks
406     HandleInterface::open();
407 
408     // read from file if it already exists, other wise
409     // we start out with a blank slate
410     if( utils::is_file( path() ) )
411     {
412         // read if handle is not 'write' only and we aren't truncating
413         if( open_mode_read() && !open_mode_truncate() )
414         {
415             // read from file
416             io::load(path(),
417                      protocol(),
418                      options(),
419                      m_node);
420         }
421         else
422         {
423             m_node.reset();
424         }
425     }
426     else if( open_mode_read_only() ) // fail on read only if file doesn't exist
427     {
428         CONDUIT_ERROR("path: \""
429                       << path()
430                       << "\" does not exist, cannot open read only "
431                       << "(mode = '" << open_mode() << "')");
432     }
433     else
434     {
435         // make sure we can actually write to this location
436         // we don't want to fail on close if the path
437         // is bogus
438         io::save(m_node,
439                  path(),
440                  protocol(),
441                  options());
442     }
443 
444     m_open = true;
445 }
446 
447 //-----------------------------------------------------------------------------
448 bool
is_open() const449 BasicHandle::is_open() const
450 {
451     return m_open;
452 }
453 
454 //-----------------------------------------------------------------------------
455 void
read(Node & node)456 BasicHandle::read(Node &node)
457 {
458     Node opts;
459     read(node, opts);
460 }
461 
462 //-----------------------------------------------------------------------------
463 void
read(Node & node,const Node & opts)464 BasicHandle::read(Node &node, const Node& opts)
465 {
466     CONDUIT_UNUSED(opts);
467     // note: wrong mode errors are handled before dispatch to interface
468 
469     node.update(m_node);
470 }
471 
472 //-----------------------------------------------------------------------------
473 void
read(const std::string & path,Node & node)474 BasicHandle::read(const std::string &path,
475                   Node &node)
476 {
477     Node opts;
478     read(path, node, opts);
479 }
480 
481 //-----------------------------------------------------------------------------
482 void
read(const std::string & path,Node & node,const Node & opts)483 BasicHandle::read(const std::string &path,
484                   Node &node,
485                   const Node &opts)
486 {
487     CONDUIT_UNUSED(opts);
488     // note: wrong mode errors are handled before dispatch to interface
489 
490     if(m_node.has_path(path))
491     {
492         node.update(m_node[path]);
493     }
494 }
495 
496 //-----------------------------------------------------------------------------
497 void
write(const Node & node)498 BasicHandle::write(const Node &node)
499 {
500     Node opts;
501     write(node, opts);
502 }
503 
504 //-----------------------------------------------------------------------------
505 void
write(const Node & node,const Node & opts)506 BasicHandle::write(const Node &node,
507                    const Node &opts)
508 {
509     CONDUIT_UNUSED(opts);
510     // note: wrong mode errors are handled before dispatch to interface
511 
512     m_node.update(node);
513 }
514 
515 
516 //-----------------------------------------------------------------------------
517 void
write(const Node & node,const std::string & path)518 BasicHandle::write(const Node &node,
519                    const std::string &path)
520 {
521     Node opts;
522     write(node, path, opts);
523 }
524 
525 //-----------------------------------------------------------------------------
526 void
write(const Node & node,const std::string & path,const Node & opts)527 BasicHandle::write(const Node &node,
528                    const std::string &path,
529                    const Node& opts)
530 {
531     CONDUIT_UNUSED(opts);
532     // note: wrong mode errors are handled before dispatch to interface
533 
534     m_node[path].update(node);
535 }
536 
537 //-----------------------------------------------------------------------------
538 void
list_child_names(std::vector<std::string> & res)539 BasicHandle::list_child_names(std::vector<std::string> &res)
540 {
541     // note: wrong mode errors are handled before dispatch to interface
542 
543     res = m_node.child_names();
544 }
545 
546 //-----------------------------------------------------------------------------
547 void
list_child_names(const std::string & path,std::vector<std::string> & res)548 BasicHandle::list_child_names(const std::string &path,
549                               std::vector<std::string> &res)
550 {
551     // note: wrong mode errors are handled before dispatch to interface
552 
553     res.clear();
554     if(m_node.has_path(path))
555         res = m_node[path].child_names();
556 }
557 
558 //-----------------------------------------------------------------------------
559 void
remove(const std::string & path)560 BasicHandle::remove(const std::string &path)
561 {
562     // note: wrong mode errors are handled before dispatch to interface
563 
564     m_node.remove(path);
565 }
566 
567 //-----------------------------------------------------------------------------
568 bool
has_path(const std::string & path)569 BasicHandle::has_path(const std::string &path)
570 {
571     // note: wrong mode errors are handled before dispatch to interface
572 
573     return m_node.has_path(path);
574 }
575 
576 //-----------------------------------------------------------------------------
577 void
close()578 BasicHandle::close()
579 {
580     if(m_open && !open_mode_read_only() )
581     {
582         // here is where it actually gets realized on disk
583         io::save(m_node,
584                  path(),
585                  protocol(),
586                  options());
587         m_node.reset();
588         m_open = false;
589     }
590 }
591 
592 
593 //-----------------------------------------------------------------------------
594 // HDF5Handle Implementation
595 //-----------------------------------------------------------------------------
596 //-----------------------------------------------------------------------------
597 //-----------------------------------------------------------------------------
598 #ifdef CONDUIT_RELAY_IO_HDF5_ENABLED
599 //-----------------------------------------------------------------------------
600 //-----------------------------------------------------------------------------
601 //-----------------------------------------------------------------------------
HDF5Handle(const std::string & path,const std::string & protocol,const Node & options)602 HDF5Handle::HDF5Handle(const std::string &path,
603                        const std::string &protocol,
604                        const Node &options)
605 : HandleInterface(path,protocol,options),
606   m_h5_id(-1)
607 {
608     // empty
609 }
610 //-----------------------------------------------------------------------------
~HDF5Handle()611 HDF5Handle::~HDF5Handle()
612 {
613     close();
614 }
615 
616 //-----------------------------------------------------------------------------
617 void
open()618 HDF5Handle::open()
619 {
620     close();
621 
622     // call base class method, which does final sanity checks
623     // and processes standard options (mode = "rw", etc)
624     HandleInterface::open();
625 
626     if( utils::is_file( path() ) )
627     {
628         // check open mode to select proper hdf5 call
629 
630         if( open_mode_read_only() )
631         {
632             m_h5_id = hdf5_open_file_for_read( path() );
633         } // support write with append
634         else if ( open_mode_append() )
635         {
636             m_h5_id = hdf5_open_file_for_read_write( path() );
637         } // support write with truncate
638         else if ( open_mode_truncate() )
639         {
640             m_h5_id = hdf5_create_file( path() );
641         }
642     }
643     else if(  open_mode_read_only() )
644     {
645         CONDUIT_ERROR("path: \""
646                       << path()
647                       << "\" does not exist, cannot open read only (mode = 'r')");
648     }
649     else
650     {
651         m_h5_id = hdf5_create_file( path() );
652     }
653 }
654 
655 
656 //-----------------------------------------------------------------------------
657 bool
is_open() const658 HDF5Handle::is_open() const
659 {
660     return m_h5_id != -1;
661 }
662 
663 //-----------------------------------------------------------------------------
664 void
read(Node & node)665 HDF5Handle::read(Node &node)
666 {
667     Node opts;
668     read(node, opts);
669 }
670 
671 //-----------------------------------------------------------------------------
672 void
read(Node & node,const Node & opts)673 HDF5Handle::read(Node &node,
674                  const Node &opts)
675 {
676     // note: wrong mode errors are handled before dispatch to interface
677 
678     hdf5_read(m_h5_id,opts,node);
679 }
680 
681 //-----------------------------------------------------------------------------
682 void
read(const std::string & path,Node & node)683 HDF5Handle::read(const std::string &path,
684                  Node &node)
685 {
686     Node opts;
687     read(path, node, opts);
688 }
689 
690 //-----------------------------------------------------------------------------
691 void
read(const std::string & path,Node & node,const Node & opts)692 HDF5Handle::read(const std::string &path,
693                  Node &node,
694                  const Node &opts)
695 {
696     // note: wrong mode errors are handled before dispatch to interface
697 
698     hdf5_read(m_h5_id,path,opts,node);
699 }
700 
701 //-----------------------------------------------------------------------------
702 void
write(const Node & node)703 HDF5Handle::write(const Node &node)
704 {
705     Node opts;
706     write(node, opts);
707 }
708 
709 //-----------------------------------------------------------------------------
710 void
write(const Node & node,const Node & opts)711 HDF5Handle::write(const Node &node,
712                   const Node &opts)
713 {
714     // note: wrong mode errors are handled before dispatch to interface
715 
716     // Options Push / Pop (only needed for write, since hdf5 only supports
717     // write options
718     Node prev_options;
719     if(options().has_child("hdf5"))
720     {
721         hdf5_options(prev_options);
722         hdf5_set_options(options()["hdf5"]);
723     }
724 
725     hdf5_write(node,m_h5_id, opts);
726 
727     if(!prev_options.dtype().is_empty())
728     {
729         hdf5_set_options(prev_options);
730     }
731 }
732 
733 
734 
735 //-----------------------------------------------------------------------------
736 void
write(const Node & node,const std::string & path)737 HDF5Handle::write(const Node &node,
738                   const std::string &path)
739 {
740     Node opts;
741     write(node, path, opts);
742 }
743 
744 //-----------------------------------------------------------------------------
745 void
write(const Node & node,const std::string & path,const Node & opts)746 HDF5Handle::write(const Node &node,
747                   const std::string &path,
748                   const Node &opts)
749 {
750     // note: wrong mode errors are handled before dispatch to interface
751 
752     // Options Push / Pop (only needed for write, since hdf5 only supports
753     // write options
754     Node prev_options;
755     if(options().has_child("hdf5"))
756     {
757         hdf5_options(prev_options);
758         hdf5_set_options(options()["hdf5"]);
759     }
760 
761     hdf5_write(node,m_h5_id,path,opts);
762 
763     if(!prev_options.dtype().is_empty())
764     {
765         hdf5_set_options(prev_options);
766     }
767 }
768 
769 //-----------------------------------------------------------------------------
770 void
list_child_names(std::vector<std::string> & res)771 HDF5Handle::list_child_names(std::vector<std::string> &res)
772 {
773     // note: wrong mode errors are handled before dispatch to interface
774 
775     hdf5_group_list_child_names(m_h5_id, "/", res);
776 }
777 
778 //-----------------------------------------------------------------------------
779 void
list_child_names(const std::string & path,std::vector<std::string> & res)780 HDF5Handle::list_child_names(const std::string &path,
781                              std::vector<std::string> &res)
782 {
783     // note: wrong mode errors are handled before dispatch to interface
784 
785     hdf5_group_list_child_names(m_h5_id, path, res);
786 }
787 
788 //-----------------------------------------------------------------------------
789 void
remove(const std::string & path)790 HDF5Handle::remove(const std::string &path)
791 {
792     // note: wrong mode errors are handled before dispatch to interface
793 
794     hdf5_remove_path(m_h5_id,path);
795 }
796 
797 //-----------------------------------------------------------------------------
798 bool
has_path(const std::string & path)799 HDF5Handle::has_path(const std::string &path)
800 {
801     // note: wrong mode errors are handled before dispatch to interface
802 
803     return hdf5_has_path(m_h5_id,path);
804 }
805 
806 
807 //-----------------------------------------------------------------------------
808 void
close()809 HDF5Handle::close()
810 {
811     if(m_h5_id >= 0)
812     {
813         hdf5_close_file(m_h5_id);
814     }
815     m_h5_id = -1;
816 }
817 
818 //-----------------------------------------------------------------------------
819 //-----------------------------------------------------------------------------
820 #endif
821 //-----------------------------------------------------------------------------
822 //-----------------------------------------------------------------------------
823 
824 
825 //-----------------------------------------------------------------------------
826 // IOHandle Implementation
827 //-----------------------------------------------------------------------------
828 
829 //-----------------------------------------------------------------------------
IOHandle()830 IOHandle::IOHandle()
831 : m_handle(NULL)
832 {
833 
834 }
835 
836 //-----------------------------------------------------------------------------
~IOHandle()837 IOHandle::~IOHandle()
838 {
839     close();
840 }
841 
842 //-----------------------------------------------------------------------------
843 void
open(const std::string & path)844 IOHandle::open(const std::string &path)
845 {
846     close();
847     m_handle = HandleInterface::create(path);
848     if(m_handle != NULL)
849     {
850         m_handle->open();
851     }
852 }
853 
854 //-----------------------------------------------------------------------------
855 void
open(const std::string & path,const std::string & protocol)856 IOHandle::open(const std::string &path,
857                const std::string &protocol)
858 {
859     close();
860     m_handle = HandleInterface::create(path, protocol);
861     if(m_handle != NULL)
862     {
863         m_handle->open();
864     }
865 }
866 
867 //-----------------------------------------------------------------------------
868 void
open(const std::string & path,const Node & options)869 IOHandle::open(const std::string &path,
870                const Node &options)
871 {
872     close();
873     m_handle = HandleInterface::create(path, options);
874     if(m_handle != NULL)
875     {
876         m_handle->open();
877     }
878 }
879 
880 //-----------------------------------------------------------------------------
881 void
open(const std::string & path,const std::string & protocol,const Node & options)882 IOHandle::open(const std::string &path,
883                const std::string &protocol,
884                const Node &options)
885 {
886     close();
887     m_handle = HandleInterface::create(path, protocol, options);
888     if(m_handle != NULL)
889     {
890         m_handle->open();
891     }
892 }
893 
894 //-----------------------------------------------------------------------------
895 bool
is_open() const896 IOHandle::is_open() const
897 {
898     bool res = false;
899 
900     if(m_handle != NULL)
901     {
902         res = m_handle->is_open();
903     }
904 
905     return res;
906 }
907 
908 //-----------------------------------------------------------------------------
909 void
read(Node & node)910 IOHandle::read(Node &node)
911 {
912     Node opts;
913     read(node,opts);
914 }
915 
916 //-----------------------------------------------------------------------------
917 void
read(Node & node,const Node & opts)918 IOHandle::read(Node &node,
919                const Node &opts)
920 {
921     if(m_handle != NULL)
922     {
923         if( m_handle->open_mode_write_only() )
924         {
925             CONDUIT_ERROR("IOHandle: cannot read, handle is write only"
926                           " (mode = '" << m_handle->open_mode() << "')");
927         }
928 
929         m_handle->read(node,opts);
930     }
931     else
932     {
933         CONDUIT_ERROR("Invalid or closed handle.");
934     }
935 }
936 
937 //-----------------------------------------------------------------------------
938 void
read(const std::string & path,Node & node)939 IOHandle::read(const std::string &path,
940                Node &node)
941 {
942     Node opts;
943     read(path,node,opts);
944 }
945 
946 //-----------------------------------------------------------------------------
947 void
read(const std::string & path,Node & node,const Node & opts)948 IOHandle::read(const std::string &path,
949                Node &node,
950                const Node &opts)
951 {
952     if(m_handle != NULL)
953     {
954         if( m_handle->open_mode_write_only() )
955         {
956             CONDUIT_ERROR("IOHandle: cannot read, handle is write only"
957                           " (mode = '" << m_handle->open_mode() << "')");
958         }
959 
960         if(path.empty())
961         {
962             m_handle->read(node, opts);
963         }
964         else
965         {
966             m_handle->read(path, node, opts);
967         }
968     }
969     else
970     {
971         CONDUIT_ERROR("Invalid or closed handle.");
972     }
973 }
974 
975 //-----------------------------------------------------------------------------
976 void
write(const Node & node)977 IOHandle::write(const Node &node)
978 {
979     Node opts;
980     write(node,opts);
981 }
982 
983 //-----------------------------------------------------------------------------
984 void
write(const Node & node,const Node & opts)985 IOHandle::write(const Node &node,
986                 const Node &opts)
987 {
988     if(m_handle != NULL)
989     {
990         if( m_handle->open_mode_read_only() )
991         {
992             CONDUIT_ERROR("IOHandle: cannot write, handle is read only"
993                           " (mode = '" << m_handle->open_mode() << "')");
994         }
995 
996         m_handle->write(node, opts);
997     }
998     else
999     {
1000         CONDUIT_ERROR("Invalid or closed handle.");
1001     }
1002 }
1003 
1004 //-----------------------------------------------------------------------------
1005 void
write(const Node & node,const std::string & path)1006 IOHandle::write(const Node &node,
1007                 const std::string &path)
1008 {
1009     Node opts;
1010     write(node,path,opts);
1011 }
1012 
1013 //-----------------------------------------------------------------------------
1014 void
write(const Node & node,const std::string & path,const Node & opts)1015 IOHandle::write(const Node &node,
1016                 const std::string &path,
1017                 const Node &opts)
1018 {
1019     if(m_handle != NULL)
1020     {
1021         if( m_handle->open_mode_read_only() )
1022         {
1023             CONDUIT_ERROR("IOHandle: cannot write, handle is read only"
1024                           " (mode = '" << m_handle->open_mode() << "')");
1025         }
1026 
1027         m_handle->write(node, path, opts);
1028     }
1029     else
1030     {
1031         CONDUIT_ERROR("Invalid or closed handle.");
1032     }
1033 
1034 }
1035 
1036 //-----------------------------------------------------------------------------
1037 void
remove(const std::string & path)1038 IOHandle::remove(const std::string &path)
1039 {
1040     if(m_handle != NULL)
1041     {
1042          if( m_handle->open_mode_read_only() )
1043          {
1044              CONDUIT_ERROR("IOHandle: cannot remove path, handle is read only"
1045                            " (mode = '" << m_handle->open_mode() << "')");
1046          }
1047 
1048         m_handle->remove(path);
1049     }
1050     else
1051     {
1052         CONDUIT_ERROR("Invalid or closed handle.");
1053     }
1054 }
1055 
1056 //-----------------------------------------------------------------------------
1057 void
list_child_names(std::vector<std::string> & names)1058 IOHandle::list_child_names(std::vector<std::string> &names)
1059 {
1060     names.clear();
1061     if(m_handle != NULL)
1062     {
1063          if( m_handle->open_mode_write_only() )
1064          {
1065              CONDUIT_ERROR("IOHandle: cannot list_child_names, handle is"
1066                            " write only"
1067                            " (mode = '" << m_handle->open_mode() << "')");
1068          }
1069 
1070         return m_handle->list_child_names(names);
1071     }
1072     else
1073     {
1074         CONDUIT_ERROR("Invalid or closed handle.");
1075     }
1076 }
1077 
1078 
1079 //-----------------------------------------------------------------------------
1080 void
list_child_names(const std::string & path,std::vector<std::string> & names)1081 IOHandle::list_child_names(const std::string &path,
1082                            std::vector<std::string> &names)
1083 {
1084     names.clear();
1085     if(m_handle != NULL)
1086     {
1087          if( m_handle->open_mode_write_only() )
1088          {
1089              CONDUIT_ERROR("IOHandle: cannot list_child_names, handle is"
1090                            " write only"
1091                            " (mode = '" << m_handle->open_mode() << "')");
1092          }
1093 
1094         return m_handle->list_child_names(path, names);
1095     }
1096     else
1097     {
1098         CONDUIT_ERROR("Invalid or closed handle.");
1099     }
1100 }
1101 
1102 //-----------------------------------------------------------------------------
1103 bool
has_path(const std::string & path)1104 IOHandle::has_path(const std::string &path)
1105 {
1106     if(m_handle != NULL)
1107     {
1108         if( m_handle->open_mode_write_only() )
1109         {
1110             CONDUIT_ERROR("IOHandle: cannot call has_path, handle is write"
1111                            " only"
1112                            " (mode = '" << m_handle->open_mode() << "')");
1113         }
1114         return m_handle->has_path(path);
1115     }
1116     else
1117     {
1118         CONDUIT_ERROR("Invalid or closed handle.");
1119     }
1120 
1121     return false;
1122 }
1123 
1124 //-----------------------------------------------------------------------------
1125 void
close()1126 IOHandle::close()
1127 {
1128     if(m_handle != NULL)
1129     {
1130         m_handle->close();
1131         delete m_handle;
1132         m_handle = NULL;
1133     }
1134     // else, ignore ...
1135 }
1136 
1137 
1138 }
1139 //-----------------------------------------------------------------------------
1140 // -- end conduit::relay::<mpi>::io --
1141 //-----------------------------------------------------------------------------
1142 
1143 #ifdef CONDUIT_RELAY_IO_MPI_ENABLED
1144 }
1145 //-----------------------------------------------------------------------------
1146 // -- begin conduit::relay::mpi --
1147 //-----------------------------------------------------------------------------
1148 #endif
1149 
1150 }
1151 //-----------------------------------------------------------------------------
1152 // -- end conduit::relay --
1153 //-----------------------------------------------------------------------------
1154 
1155 }
1156 //-----------------------------------------------------------------------------
1157 // -- end conduit:: --
1158 //-----------------------------------------------------------------------------
1159