1 #ifndef XTENSOR_IO_DISK_HANDLER_HPP
2 #define XTENSOR_IO_DISK_HANDLER_HPP
3 
4 #include <ghc/filesystem.hpp>
5 #include <xtensor/xarray.hpp>
6 #include <xtensor/xexpression.hpp>
7 #include "xio_stream_wrapper.hpp"
8 #include "xfile_array.hpp"
9 
10 namespace fs = ghc::filesystem;
11 
12 namespace xt
13 {
14     struct xio_disk_config
15     {
16         bool create_directories;
17     };
18 
19     template <class C>
20     class xio_disk_handler
21     {
22     public:
23         using io_config = xio_disk_config;
24 
25         xio_disk_handler();
26 
27         template <class E>
28         void write(const xexpression<E>& expression, const std::string& path, xfile_dirty dirty);
29 
30         template <class ET>
31         void read(ET& array, const std::string& path);
32 
33         void configure(const C& format_config, const xio_disk_config& io_config);
34         void configure_io(const xio_disk_config& io_config);
35 
36     private:
37 
38         C m_format_config;
39         bool m_create_directories;
40     };
41 
42     template <class C>
xio_disk_handler()43     xio_disk_handler<C>::xio_disk_handler()
44         : m_create_directories(true)
45     {
46     }
47 
48     template <class C>
49     template <class E>
write(const xexpression<E> & expression,const std::string & path,xfile_dirty dirty)50     inline void xio_disk_handler<C>::write(const xexpression<E>& expression, const std::string& path, xfile_dirty dirty)
51     {
52         if (m_format_config.will_dump(dirty))
53         {
54             if (m_create_directories)
55             {
56                 // maybe create directories
57                 std::size_t i = path.rfind('/');
58                 if (i != std::string::npos)
59                 {
60                     fs::path directory = path.substr(0, i);
61                     if (fs::exists(directory))
62                     {
63                         if (!fs::is_directory(directory))
64                         {
65                             XTENSOR_THROW(std::runtime_error, "Path is not a directory: " + std::string(directory));
66                         }
67                     }
68                     else
69                     {
70                         fs::create_directories(directory);
71                     }
72                 }
73             }
74             std::ofstream out_file(path, std::ofstream::binary);
75             if (out_file.is_open())
76             {
77                 auto s = xostream_wrapper(out_file);
78                 dump_file(s, expression, m_format_config);
79             }
80             else
81             {
82                 XTENSOR_THROW(std::runtime_error, "write: failed to open file " + path);
83             }
84         }
85     }
86 
87     template <class C>
88     template <class ET>
read(ET & array,const std::string & path)89     inline void xio_disk_handler<C>::read(ET& array, const std::string& path)
90     {
91         std::ifstream in_file(path, std::ifstream::binary);
92         if (in_file.is_open())
93         {
94             auto s = xistream_wrapper(in_file);
95             load_file<ET>(s, array, m_format_config);
96         }
97         else
98         {
99             XTENSOR_THROW(std::runtime_error, "read: failed to open file " + path);
100         }
101     }
102 
103     template <class C>
configure(const C & format_config,const xio_disk_config & io_config)104     inline void xio_disk_handler<C>::configure(const C& format_config, const xio_disk_config& io_config)
105     {
106         m_format_config = format_config;
107         m_create_directories = io_config.create_directories;
108     }
109 
110     template <class C>
configure_io(const xio_disk_config & io_config)111     inline void xio_disk_handler<C>::configure_io(const xio_disk_config& io_config)
112     {
113         m_create_directories = io_config.create_directories;
114     }
115 
116 }
117 
118 #endif
119