From 10f61f03f0a0149e6c62508b276210f614ff8c52 Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Fri, 17 May 2024 13:09:12 +0100 Subject: [PATCH] optimise reading/writing for contiguous arrays --- src/include/stir/IO/read_data.h | 1 + src/include/stir/IO/read_data.inl | 5 +++ src/include/stir/IO/read_data_1d.h | 8 ++--- src/include/stir/IO/read_data_1d.inl | 28 ++++++++-------- src/include/stir/IO/write_data_1d.h | 8 ++--- src/include/stir/IO/write_data_1d.inl | 48 +++++++++++++-------------- 6 files changed, 52 insertions(+), 46 deletions(-) diff --git a/src/include/stir/IO/read_data.h b/src/include/stir/IO/read_data.h index a898eeb5e9..1baefc8185 100644 --- a/src/include/stir/IO/read_data.h +++ b/src/include/stir/IO/read_data.h @@ -2,6 +2,7 @@ #define __stir_IO_read_data_H__ /* Copyright (C) 2004- 2007, Hammersmith Imanet Ltd + Copyright (C) 2024, University College London This file is part of STIR. SPDX-License-Identifier: Apache-2.0 diff --git a/src/include/stir/IO/read_data.inl b/src/include/stir/IO/read_data.inl index 7351576c88..e8c6b30818 100644 --- a/src/include/stir/IO/read_data.inl +++ b/src/include/stir/IO/read_data.inl @@ -1,5 +1,6 @@ /* Copyright (C) 2004- 2007, Hammersmith Imanet Ltd + Copyright (C) 2024, University College London This file is part of STIR. SPDX-License-Identifier: Apache-2.0 @@ -34,6 +35,10 @@ template inline Succeeded read_data_help(is_not_1d, IStreamT& s, Array& data, const ByteOrder byte_order) { + if (data.is_contiguous()) + return read_data_1d(s, data, byte_order); + + // otherwise, recurse for (typename Array::iterator iter = data.begin(); iter != data.end(); ++iter) { if (read_data(s, *iter, byte_order) == Succeeded::no) diff --git a/src/include/stir/IO/read_data_1d.h b/src/include/stir/IO/read_data_1d.h index 0bd70136e6..1784df7eaf 100644 --- a/src/include/stir/IO/read_data_1d.h +++ b/src/include/stir/IO/read_data_1d.h @@ -34,15 +34,15 @@ namespace detail This function might propagate any exceptions by std::istream::read. */ -template -inline Succeeded read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order); +template +inline Succeeded read_data_1d(std::istream& s, Array& data, const ByteOrder byte_order); /* \ingroup Array_IO_detail \brief This is the (internal) function that does the actual reading from a FILE*. \internal */ -template -inline Succeeded read_data_1d(FILE*&, Array<1, elemT>& data, const ByteOrder byte_order); +template +inline Succeeded read_data_1d(FILE*&, Array& data, const ByteOrder byte_order); } // end namespace detail END_NAMESPACE_STIR diff --git a/src/include/stir/IO/read_data_1d.inl b/src/include/stir/IO/read_data_1d.inl index d0c8a2d713..cd336bba30 100644 --- a/src/include/stir/IO/read_data_1d.inl +++ b/src/include/stir/IO/read_data_1d.inl @@ -27,9 +27,9 @@ namespace detail /***************** version for istream *******************************/ -template +template Succeeded -read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order) +read_data_1d(std::istream& s, Array& data, const ByteOrder byte_order) { if (!s || (dynamic_cast(&s) != 0 && !dynamic_cast(&s)->is_open()) || (dynamic_cast(&s) != 0 && !dynamic_cast(&s)->is_open())) @@ -41,9 +41,9 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order) // note: find num_to_read (using size()) outside of s.read() function call // otherwise Array::check_state() in size() might abort if // get_data_ptr() is called before size() (which is compiler dependent) - const std::streamsize num_to_read = static_cast(data.size()) * sizeof(elemT); - s.read(reinterpret_cast(data.get_data_ptr()), num_to_read); - data.release_data_ptr(); + const std::streamsize num_to_read = static_cast(data.size_all()) * sizeof(elemT); + s.read(reinterpret_cast(data.get_full_data_ptr()), num_to_read); + data.release_full_data_ptr(); if (!s) { @@ -53,8 +53,8 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order) if (!byte_order.is_native_order()) { - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data[i]); + for (auto iter = data.begin_all(); iter != data.end_all(); ++iter) + ByteOrder::swap_order(*iter); } return Succeeded::yes; @@ -63,9 +63,9 @@ read_data_1d(std::istream& s, Array<1, elemT>& data, const ByteOrder byte_order) /***************** version for FILE *******************************/ // largely a copy of above, but with calls to stdio function -template +template Succeeded -read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order) +read_data_1d(FILE*& fptr_ref, Array& data, const ByteOrder byte_order) { FILE* fptr = fptr_ref; if (fptr == NULL || ferror(fptr)) @@ -77,9 +77,9 @@ read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order) // note: find num_to_read (using size()) outside of s.read() function call // otherwise Array::check_state() in size() might abort if // get_data_ptr() is called before size() (which is compiler dependent) - const std::size_t num_to_read = static_cast(data.size()); - const std::size_t num_read = fread(reinterpret_cast(data.get_data_ptr()), sizeof(elemT), num_to_read, fptr); - data.release_data_ptr(); + const std::size_t num_to_read = static_cast(data.size_all()); + const std::size_t num_read = fread(reinterpret_cast(data.get_full_data_ptr()), sizeof(elemT), num_to_read, fptr); + data.release_full_data_ptr(); if (ferror(fptr) || num_to_read != num_read) { @@ -89,8 +89,8 @@ read_data_1d(FILE*& fptr_ref, Array<1, elemT>& data, const ByteOrder byte_order) if (!byte_order.is_native_order()) { - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data[i]); + for (auto iter = data.begin_all(); iter != data.end_all(); ++iter) + ByteOrder::swap_order(*iter); } return Succeeded::yes; diff --git a/src/include/stir/IO/write_data_1d.h b/src/include/stir/IO/write_data_1d.h index e376210366..c88451f5da 100644 --- a/src/include/stir/IO/write_data_1d.h +++ b/src/include/stir/IO/write_data_1d.h @@ -35,9 +35,9 @@ namespace detail This function does not throw any exceptions. Exceptions thrown by std::ostream::write are caught. */ -template +template inline Succeeded -write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data); +write_data_1d(std::ostream& s, const Array& data, const ByteOrder byte_order, const bool can_corrupt_data); /*! \ingroup Array_IO_detail \brief This is an internal function called by \c write_data(). It does the actual writing to \c FILE* using stdio functions. @@ -45,9 +45,9 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte This function does not throw any exceptions. */ -template +template inline Succeeded -write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data); +write_data_1d(FILE*& fptr_ref, const Array& data, const ByteOrder byte_order, const bool can_corrupt_data); } // namespace detail END_NAMESPACE_STIR diff --git a/src/include/stir/IO/write_data_1d.inl b/src/include/stir/IO/write_data_1d.inl index 8a704d9852..5343f31baf 100644 --- a/src/include/stir/IO/write_data_1d.inl +++ b/src/include/stir/IO/write_data_1d.inl @@ -27,9 +27,9 @@ namespace detail /***************** version for ostream *******************************/ -template +template inline Succeeded -write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data) +write_data_1d(std::ostream& s, const Array& data, const ByteOrder byte_order, const bool can_corrupt_data) { if (!s || (dynamic_cast(&s) != 0 && !dynamic_cast(&s)->is_open()) || (dynamic_cast(&s) != 0 && !dynamic_cast(&s)->is_open())) @@ -44,7 +44,7 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte /* if (!byte_order.is_native_order()) { - Array<1, elemT> a_copy(data); + Array a_copy(data); for(int i=data.get_min_index(); i<=data.get_max_index(); i++) ByteOrder::swap_order(a_copy[i]); return write_data(s, a_copy, ByteOrder::native, true); @@ -52,32 +52,32 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte */ if (!byte_order.is_native_order()) { - Array<1, elemT>& data_ref = const_cast&>(data); - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data_ref[i]); + Array& data_ref = const_cast&>(data); + for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter) + ByteOrder::swap_order(*iter); } // note: find num_to_write (using size()) outside of s.write() function call // otherwise Array::check_state() in size() might abort if // get_const_data_ptr() is called before size() (which is compiler dependent) - const std::streamsize num_to_write = static_cast(data.size()) * sizeof(elemT); + const std::streamsize num_to_write = static_cast(data.size_all()) * sizeof(elemT); bool writing_ok = true; try { - s.write(reinterpret_cast(data.get_const_data_ptr()), num_to_write); + s.write(reinterpret_cast(data.get_const_full_data_ptr()), num_to_write); } catch (...) { writing_ok = false; } - data.release_const_data_ptr(); + data.release_const_full_data_ptr(); if (!can_corrupt_data && !byte_order.is_native_order()) { - Array<1, elemT>& data_ref = const_cast&>(data); - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data_ref[i]); + Array& data_ref = const_cast&>(data); + for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter) + ByteOrder::swap_order(*iter); } if (!writing_ok || !s) @@ -92,9 +92,9 @@ write_data_1d(std::ostream& s, const Array<1, elemT>& data, const ByteOrder byte /***************** version for FILE *******************************/ // largely a copy of above, but with calls to stdio function -template +template inline Succeeded -write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte_order, const bool can_corrupt_data) +write_data_1d(FILE*& fptr_ref, const Array& data, const ByteOrder byte_order, const bool can_corrupt_data) { FILE* fptr = fptr_ref; if (fptr == 0 || ferror(fptr)) @@ -109,7 +109,7 @@ write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte /* if (!byte_order.is_native_order()) { - Array<1, elemT> a_copy(data); + Array a_copy(data); for(int i=data.get_min_index(); i<=data.get_max_index(); i++) ByteOrder::swap_order(a_copy[i]); return write_data(s, a_copy, ByteOrder::native, true); @@ -117,25 +117,25 @@ write_data_1d(FILE*& fptr_ref, const Array<1, elemT>& data, const ByteOrder byte */ if (!byte_order.is_native_order()) { - Array<1, elemT>& data_ref = const_cast&>(data); - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data_ref[i]); + Array& data_ref = const_cast&>(data); + for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter) + ByteOrder::swap_order(*iter); } // note: find num_to_write (using size()) outside of s.write() function call // otherwise Array::check_state() in size() might abort if // get_const_data_ptr() is called before size() (which is compiler dependent) - const std::size_t num_to_write = static_cast(data.size()); + const std::size_t num_to_write = static_cast(data.size_all()); const std::size_t num_written - = fwrite(reinterpret_cast(data.get_const_data_ptr()), sizeof(elemT), num_to_write, fptr); + = fwrite(reinterpret_cast(data.get_const_full_data_ptr()), sizeof(elemT), num_to_write, fptr); - data.release_const_data_ptr(); + data.release_const_full_data_ptr(); if (!can_corrupt_data && !byte_order.is_native_order()) { - Array<1, elemT>& data_ref = const_cast&>(data); - for (int i = data.get_min_index(); i <= data.get_max_index(); ++i) - ByteOrder::swap_order(data_ref[i]); + Array& data_ref = const_cast&>(data); + for (auto iter = data_ref.begin_all(); iter != data_ref.end_all(); ++iter) + ByteOrder::swap_order(*iter); } if (num_written != num_to_write || ferror(fptr))