Skip to content

Commit 156617a

Browse files
committed
Add file-like support in xio_binary
1 parent 4940c50 commit 156617a

File tree

3 files changed

+88
-22
lines changed

3 files changed

+88
-22
lines changed

include/xtensor-io/xgdal.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace xt
4646
}
4747

4848
/**
49-
* Get a band interleaved by yixel layout; index order = [row, column, band].
49+
* Get a band interleaved by pixel layout; index order = [row, column, band].
5050
*/
5151
inline layout layout_band_interleaved_pixel()
5252
{
@@ -346,7 +346,7 @@ namespace xt
346346
std::string driver_name;
347347

348348
/**
349-
* Options passed to to GDAL when the dataset is created (like COMPRESS=JPEG).
349+
* Options passed to GDAL when the dataset is created (like COMPRESS=JPEG).
350350
*/
351351
std::vector<std::string> creation_options;
352352

@@ -541,4 +541,4 @@ namespace xt
541541
} // namespace xt
542542

543543

544-
#endif // XTENSOR_IO_XGDAL_HPP
544+
#endif // XTENSOR_IO_XGDAL_HPP

include/xtensor-io/xio_binary.hpp

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,33 @@ namespace xt
2020
{
2121
namespace detail
2222
{
23-
template <typename T>
24-
inline xt::svector<T> load_bin_file(std::istream& stream, bool as_big_endian)
23+
// load_bin "overload" for file-like objects
24+
// we check that `fclose` can be called on them!
25+
template<typename T, class I>
26+
auto load_bin_imp(I& file, std::string& buffer)
27+
-> decltype(fclose(file), void())
2528
{
26-
std::string buffer{std::istreambuf_iterator<char>{stream}, {}};
29+
fseek(file, 0, SEEK_END);
30+
std::size_t size = ftell(file);
31+
buffer.resize(size);
32+
rewind(file);
33+
fread(&buffer[0], 1, size, file);
34+
}
35+
36+
// load_bin "overload" for stream-like objects
37+
// we check that they have a `tellg` method!
38+
template<typename T, class I>
39+
auto load_bin_imp(I& stream, std::string& buffer)
40+
-> decltype(stream.tellg(), void())
41+
{
42+
buffer = {std::istreambuf_iterator<char>{stream}, {}};
43+
}
44+
45+
template <typename T, class I>
46+
inline xt::svector<T> load_bin(I& stream, bool as_big_endian)
47+
{
48+
std::string buffer;
49+
load_bin_imp<T>(stream, buffer);
2750
std::size_t uncompressed_size = buffer.size() / sizeof(T);
2851
xt::svector<T> uncompressed_buffer(uncompressed_size);
2952
std::copy((const T*)(buffer.data()), (const T*)(buffer.data()) + uncompressed_size, uncompressed_buffer.begin());
@@ -34,8 +57,28 @@ namespace xt
3457
return uncompressed_buffer;
3558
}
3659

60+
// dump_bin "overload" for file-like objects
61+
// we check that `fclose` can be called on them!
62+
template <class O>
63+
auto dump_bin_imp(O& file, const char* uncompressed_buffer, std::size_t uncompressed_size)
64+
-> decltype(fclose(file), void())
65+
{
66+
fwrite(uncompressed_buffer, 1, uncompressed_size, file);
67+
fflush(file);
68+
}
69+
70+
// dump_bin "overload" for stream-like objects
71+
// we check that they have a `tellp` method!
72+
template <class O>
73+
auto dump_bin_imp(O& stream, const char* uncompressed_buffer, std::size_t uncompressed_size)
74+
-> decltype(stream.tellp(), void())
75+
{
76+
stream.write(uncompressed_buffer, std::streamsize(uncompressed_size));
77+
stream.flush();
78+
}
79+
3780
template <class O, class E>
38-
inline void dump_bin_stream(O& stream, const xexpression<E>& e, bool as_big_endian)
81+
inline void dump_bin(O& stream, const xexpression<E>& e, bool as_big_endian)
3982
{
4083
using value_type = typename E::value_type;
4184
const E& ex = e.derived_cast();
@@ -56,21 +99,26 @@ namespace xt
5699
{
57100
uncompressed_buffer = reinterpret_cast<const char*>(eval_ex.data());
58101
}
59-
stream.write(uncompressed_buffer, std::streamsize(uncompressed_size));
60-
stream.flush();
102+
dump_bin_imp(stream, uncompressed_buffer, uncompressed_size);
61103
}
62104
} // namespace detail
63105

106+
template <typename E, class O>
107+
inline void dump_bin(O& stream, const xexpression<E>& e, bool as_big_endian=is_big_endian())
108+
{
109+
detail::dump_bin(stream, e, as_big_endian);
110+
}
111+
64112
/**
65113
* Save xexpression to binary format
66114
*
67115
* @param stream An output stream to which to dump the data
68116
* @param e the xexpression
69117
*/
70118
template <typename E>
71-
inline void dump_bin(std::ostream& stream, const xexpression<E>& e, bool as_big_endian=is_big_endian())
119+
inline void dump_bin(std::ofstream& stream, const xexpression<E>& e, bool as_big_endian=is_big_endian())
72120
{
73-
detail::dump_bin_stream(stream, e, as_big_endian);
121+
detail::dump_bin(stream, e, as_big_endian);
74122
}
75123

76124
/**
@@ -87,7 +135,7 @@ namespace xt
87135
{
88136
std::runtime_error("IO Error: failed to open file");
89137
}
90-
detail::dump_bin_stream(stream, e, as_big_endian);
138+
detail::dump_bin(stream, e, as_big_endian);
91139
}
92140

93141
/**
@@ -99,7 +147,7 @@ namespace xt
99147
inline std::string dump_bin(const xexpression<E>& e, bool as_big_endian=is_big_endian())
100148
{
101149
std::stringstream stream;
102-
detail::dump_bin_stream(stream, e, as_big_endian);
150+
detail::dump_bin(stream, e, as_big_endian);
103151
return stream.str();
104152
}
105153

@@ -112,10 +160,10 @@ namespace xt
112160
* Fortran format
113161
* @return xarray with contents from binary file
114162
*/
115-
template <typename T, layout_type L = layout_type::dynamic>
116-
inline auto load_bin(std::istream& stream, bool as_big_endian=is_big_endian())
163+
template <typename T, layout_type L = layout_type::dynamic, class I>
164+
inline auto load_bin(I& stream, bool as_big_endian=is_big_endian())
117165
{
118-
xt::svector<T> uncompressed_buffer = detail::load_bin_file<T>(stream, as_big_endian);
166+
xt::svector<T> uncompressed_buffer = detail::load_bin<T>(stream, as_big_endian);
119167
std::vector<std::size_t> shape = {uncompressed_buffer.size()};
120168
auto array = adapt(std::move(uncompressed_buffer), shape);
121169
return array;
@@ -170,8 +218,8 @@ namespace xt
170218
}
171219
};
172220

173-
template <class E>
174-
void load_file(std::istream& stream, xexpression<E>& e, const xio_binary_config& config)
221+
template <class E, class I>
222+
void load_file(I& stream, xexpression<E>& e, const xio_binary_config& config)
175223
{
176224
E& ex = e.derived_cast();
177225
auto shape = ex.shape();
@@ -186,8 +234,8 @@ namespace xt
186234
}
187235
}
188236

189-
template <class E>
190-
void dump_file(std::ostream& stream, const xexpression<E> &e, const xio_binary_config& config)
237+
template <class E, class O>
238+
void dump_file(O& stream, const xexpression<E> &e, const xio_binary_config& config)
191239
{
192240
dump_bin(stream, e, config.big_endian);
193241
}

test/test_xio_binary.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313

1414
namespace xt
1515
{
16-
TEST(xio_binary, dump_load)
16+
TEST(xio_binary, dump_load_stream)
1717
{
1818
xtensor<double, 2> data
1919
{{ 1.0, 2.0, 3.0, 4.0},
2020
{10.0, 12.0, 15.0, 18.0}};
2121

22-
const char* fname = "data.bin";
22+
const char* fname = "data_stream.bin";
2323
std::ofstream out_file(fname, std::ofstream::binary);
2424
dump_file(out_file, data, xio_binary_config());
2525

@@ -30,4 +30,22 @@ namespace xt
3030

3131
ASSERT_TRUE(all(equal(a, data)));
3232
}
33+
34+
TEST(xio_binary, dump_load_file)
35+
{
36+
xtensor<double, 2> data
37+
{{ 1.0, 2.0, 3.0, 4.0},
38+
{10.0, 12.0, 15.0, 18.0}};
39+
40+
const char* fname = "data_file.bin";
41+
FILE* out_file = fopen(fname, "wb");
42+
dump_file(out_file, data, xio_binary_config());
43+
44+
xarray<double> a;
45+
FILE* in_file = fopen(fname, "rb");
46+
load_file(in_file, a, xio_binary_config());
47+
a.reshape({2, 4});
48+
49+
ASSERT_TRUE(all(equal(a, data)));
50+
}
3351
}

0 commit comments

Comments
 (0)