Skip to content

Commit 10f61f0

Browse files
optimise reading/writing for contiguous arrays
1 parent 715ede8 commit 10f61f0

File tree

6 files changed

+52
-46
lines changed

6 files changed

+52
-46
lines changed

Diff for: src/include/stir/IO/read_data.h

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define __stir_IO_read_data_H__
33
/*
44
Copyright (C) 2004- 2007, Hammersmith Imanet Ltd
5+
Copyright (C) 2024, University College London
56
This file is part of STIR.
67
78
SPDX-License-Identifier: Apache-2.0

Diff for: src/include/stir/IO/read_data.inl

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
Copyright (C) 2004- 2007, Hammersmith Imanet Ltd
3+
Copyright (C) 2024, University College London
34
This file is part of STIR.
45
56
SPDX-License-Identifier: Apache-2.0
@@ -34,6 +35,10 @@ template <int num_dimensions, class IStreamT, class elemT>
3435
inline Succeeded
3536
read_data_help(is_not_1d, IStreamT& s, Array<num_dimensions, elemT>& data, const ByteOrder byte_order)
3637
{
38+
if (data.is_contiguous())
39+
return read_data_1d(s, data, byte_order);
40+
41+
// otherwise, recurse
3742
for (typename Array<num_dimensions, elemT>::iterator iter = data.begin(); iter != data.end(); ++iter)
3843
{
3944
if (read_data(s, *iter, byte_order) == Succeeded::no)

Diff for: src/include/stir/IO/read_data_1d.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ namespace detail
3434
3535
This function might propagate any exceptions by std::istream::read.
3636
*/
37-
template <class elemT>
38-
inline Succeeded read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order);
37+
template <int num_dimensions, class elemT>
38+
inline Succeeded read_data_1d(std::istream& s, Array<num_dimensions, elemT>& data, const ByteOrder byte_order);
3939

4040
/* \ingroup Array_IO_detail
4141
\brief This is the (internal) function that does the actual reading from a FILE*.
4242
\internal
4343
*/
44-
template <class elemT>
45-
inline Succeeded read_data_1d(FILE*&, Array<1, elemT>& data, const ByteOrder byte_order);
44+
template <int num_dimensions, class elemT>
45+
inline Succeeded read_data_1d(FILE*&, Array<num_dimensions, elemT>& data, const ByteOrder byte_order);
4646

4747
} // end namespace detail
4848
END_NAMESPACE_STIR

Diff for: src/include/stir/IO/read_data_1d.inl

+14-14
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ namespace detail
2727

2828
/***************** version for istream *******************************/
2929

30-
template <class elemT>
30+
template <int num_dimensions, class elemT>
3131
Succeeded
32-
read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order)
32+
read_data_1d(std::istream& s, Array<num_dimensions, elemT>& data, const ByteOrder byte_order)
3333
{
3434
if (!s || (dynamic_cast<std::ifstream*>(&s) != 0 && !dynamic_cast<std::ifstream*>(&s)->is_open())
3535
|| (dynamic_cast<std::fstream*>(&s) != 0 && !dynamic_cast<std::fstream*>(&s)->is_open()))
@@ -41,9 +41,9 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order)
4141
// note: find num_to_read (using size()) outside of s.read() function call
4242
// otherwise Array::check_state() in size() might abort if
4343
// get_data_ptr() is called before size() (which is compiler dependent)
44-
const std::streamsize num_to_read = static_cast<std::streamsize>(data.size()) * sizeof(elemT);
45-
s.read(reinterpret_cast<char*>(data.get_data_ptr()), num_to_read);
46-
data.release_data_ptr();
44+
const std::streamsize num_to_read = static_cast<std::streamsize>(data.size_all()) * sizeof(elemT);
45+
s.read(reinterpret_cast<char*>(data.get_full_data_ptr()), num_to_read);
46+
data.release_full_data_ptr();
4747

4848
if (!s)
4949
{
@@ -53,8 +53,8 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order)
5353

5454
if (!byte_order.is_native_order())
5555
{
56-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
57-
ByteOrder::swap_order(data[i]);
56+
for (auto iter = data.begin_all(); iter != data.end_all(); ++iter)
57+
ByteOrder::swap_order(*iter);
5858
}
5959

6060
return Succeeded::yes;
@@ -63,9 +63,9 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order)
6363
/***************** version for FILE *******************************/
6464
// largely a copy of above, but with calls to stdio function
6565

66-
template <class elemT>
66+
template <int num_dimensions, class elemT>
6767
Succeeded
68-
read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order)
68+
read_data_1d(FILE*& fptr_ref, Array<num_dimensions, elemT>& data, const ByteOrder byte_order)
6969
{
7070
FILE* fptr = fptr_ref;
7171
if (fptr == NULL || ferror(fptr))
@@ -77,9 +77,9 @@ read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order)
7777
// note: find num_to_read (using size()) outside of s.read() function call
7878
// otherwise Array::check_state() in size() might abort if
7979
// get_data_ptr() is called before size() (which is compiler dependent)
80-
const std::size_t num_to_read = static_cast<std::size_t>(data.size());
81-
const std::size_t num_read = fread(reinterpret_cast<char*>(data.get_data_ptr()), sizeof(elemT), num_to_read, fptr);
82-
data.release_data_ptr();
80+
const std::size_t num_to_read = static_cast<std::size_t>(data.size_all());
81+
const std::size_t num_read = fread(reinterpret_cast<char*>(data.get_full_data_ptr()), sizeof(elemT), num_to_read, fptr);
82+
data.release_full_data_ptr();
8383

8484
if (ferror(fptr) || num_to_read != num_read)
8585
{
@@ -89,8 +89,8 @@ read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order)
8989

9090
if (!byte_order.is_native_order())
9191
{
92-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
93-
ByteOrder::swap_order(data[i]);
92+
for (auto iter = data.begin_all(); iter != data.end_all(); ++iter)
93+
ByteOrder::swap_order(*iter);
9494
}
9595

9696
return Succeeded::yes;

Diff for: src/include/stir/IO/write_data_1d.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ namespace detail
3535
This function does not throw any exceptions. Exceptions thrown by std::ostream::write
3636
are caught.
3737
*/
38-
template <class elemT>
38+
template <int num_dimensions, class elemT>
3939
inline Succeeded
40-
write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data);
40+
write_data_1d(std::ostream& s, const Array<num_dimensions, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data);
4141
/*! \ingroup Array_IO_detail
4242
\brief This is an internal function called by \c write_data(). It does the actual writing
4343
to \c FILE* using stdio functions.
4444
4545
This function does not throw any exceptions.
4646
4747
*/
48-
template <class elemT>
48+
template <int num_dimensions, class elemT>
4949
inline Succeeded
50-
write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data);
50+
write_data_1d(FILE*& fptr_ref, const Array<num_dimensions, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data);
5151
} // namespace detail
5252

5353
END_NAMESPACE_STIR

Diff for: src/include/stir/IO/write_data_1d.inl

+24-24
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ namespace detail
2727

2828
/***************** version for ostream *******************************/
2929

30-
template <class elemT>
30+
template <int num_dimensions, class elemT>
3131
inline Succeeded
32-
write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data)
32+
write_data_1d(std::ostream& s, const Array<num_dimensions, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data)
3333
{
3434
if (!s || (dynamic_cast<std::ofstream*>(&s) != 0 && !dynamic_cast<std::ofstream*>(&s)->is_open())
3535
|| (dynamic_cast<std::fstream*>(&s) != 0 && !dynamic_cast<std::fstream*>(&s)->is_open()))
@@ -44,40 +44,40 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte
4444
/*
4545
if (!byte_order.is_native_order())
4646
{
47-
Array<1, elemT> a_copy(data);
47+
Array<num_dimensions, elemT> a_copy(data);
4848
for(int i=data.get_min_index(); i<=data.get_max_index(); i++)
4949
ByteOrder::swap_order(a_copy[i]);
5050
return write_data(s, a_copy, ByteOrder::native, true);
5151
}
5252
*/
5353
if (!byte_order.is_native_order())
5454
{
55-
Array<1, elemT>& data_ref = const_cast<Array<1, elemT>&>(data);
56-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
57-
ByteOrder::swap_order(data_ref[i]);
55+
Array<num_dimensions, elemT>& data_ref = const_cast<Array<num_dimensions, elemT>&>(data);
56+
for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter)
57+
ByteOrder::swap_order(*iter);
5858
}
5959

6060
// note: find num_to_write (using size()) outside of s.write() function call
6161
// otherwise Array::check_state() in size() might abort if
6262
// get_const_data_ptr() is called before size() (which is compiler dependent)
63-
const std::streamsize num_to_write = static_cast<std::streamsize>(data.size()) * sizeof(elemT);
63+
const std::streamsize num_to_write = static_cast<std::streamsize>(data.size_all()) * sizeof(elemT);
6464
bool writing_ok = true;
6565
try
6666
{
67-
s.write(reinterpret_cast<const char*>(data.get_const_data_ptr()), num_to_write);
67+
s.write(reinterpret_cast<const char*>(data.get_const_full_data_ptr()), num_to_write);
6868
}
6969
catch (...)
7070
{
7171
writing_ok = false;
7272
}
7373

74-
data.release_const_data_ptr();
74+
data.release_const_full_data_ptr();
7575

7676
if (!can_corrupt_data && !byte_order.is_native_order())
7777
{
78-
Array<1, elemT>& data_ref = const_cast<Array<1, elemT>&>(data);
79-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
80-
ByteOrder::swap_order(data_ref[i]);
78+
Array<num_dimensions, elemT>& data_ref = const_cast<Array<num_dimensions, elemT>&>(data);
79+
for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter)
80+
ByteOrder::swap_order(*iter);
8181
}
8282

8383
if (!writing_ok || !s)
@@ -92,9 +92,9 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte
9292
/***************** version for FILE *******************************/
9393
// largely a copy of above, but with calls to stdio function
9494

95-
template <class elemT>
95+
template <int num_dimensions, class elemT>
9696
inline Succeeded
97-
write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data)
97+
write_data_1d(FILE*& fptr_ref, const Array<num_dimensions, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data)
9898
{
9999
FILE* fptr = fptr_ref;
100100
if (fptr == 0 || ferror(fptr))
@@ -109,33 +109,33 @@ write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte
109109
/*
110110
if (!byte_order.is_native_order())
111111
{
112-
Array<1, elemT> a_copy(data);
112+
Array<num_dimensions, elemT> a_copy(data);
113113
for(int i=data.get_min_index(); i<=data.get_max_index(); i++)
114114
ByteOrder::swap_order(a_copy[i]);
115115
return write_data(s, a_copy, ByteOrder::native, true);
116116
}
117117
*/
118118
if (!byte_order.is_native_order())
119119
{
120-
Array<1, elemT>& data_ref = const_cast<Array<1, elemT>&>(data);
121-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
122-
ByteOrder::swap_order(data_ref[i]);
120+
Array<num_dimensions, elemT>& data_ref = const_cast<Array<num_dimensions, elemT>&>(data);
121+
for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter)
122+
ByteOrder::swap_order(*iter);
123123
}
124124

125125
// note: find num_to_write (using size()) outside of s.write() function call
126126
// otherwise Array::check_state() in size() might abort if
127127
// get_const_data_ptr() is called before size() (which is compiler dependent)
128-
const std::size_t num_to_write = static_cast<std::size_t>(data.size());
128+
const std::size_t num_to_write = static_cast<std::size_t>(data.size_all());
129129
const std::size_t num_written
130-
= fwrite(reinterpret_cast<const char*>(data.get_const_data_ptr()), sizeof(elemT), num_to_write, fptr);
130+
= fwrite(reinterpret_cast<const char*>(data.get_const_full_data_ptr()), sizeof(elemT), num_to_write, fptr);
131131

132-
data.release_const_data_ptr();
132+
data.release_const_full_data_ptr();
133133

134134
if (!can_corrupt_data && !byte_order.is_native_order())
135135
{
136-
Array<1, elemT>& data_ref = const_cast<Array<1, elemT>&>(data);
137-
for (int i = data.get_min_index(); i <= data.get_max_index(); ++i)
138-
ByteOrder::swap_order(data_ref[i]);
136+
Array<num_dimensions, elemT>& data_ref = const_cast<Array<num_dimensions, elemT>&>(data);
137+
for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter)
138+
ByteOrder::swap_order(*iter);
139139
}
140140

141141
if (num_written != num_to_write || ferror(fptr))

0 commit comments

Comments
 (0)