diff --git a/include/openPMD/IO/ADIOS/ADIOS1IOHandlerImpl.hpp b/include/openPMD/IO/ADIOS/ADIOS1IOHandlerImpl.hpp index d7e0d921e9..b35f504ee8 100644 --- a/include/openPMD/IO/ADIOS/ADIOS1IOHandlerImpl.hpp +++ b/include/openPMD/IO/ADIOS/ADIOS1IOHandlerImpl.hpp @@ -101,7 +101,12 @@ class OPENPMDAPI_EXPORT ADIOS1IOHandlerImpl : public AbstractIOHandlerImpl m_openWriteFileHandles; std::unordered_map, ADIOS_FILE *> m_openReadFileHandles; - std::unordered_map > + struct ScheduledRead + { + ADIOS_SELECTION *selection; + std::shared_ptr data; // needed to avoid early freeing + }; + std::unordered_map > m_scheduledReads; std::unordered_map > m_attributeWrites; diff --git a/include/openPMD/IO/ADIOS/ParallelADIOS1IOHandlerImpl.hpp b/include/openPMD/IO/ADIOS/ParallelADIOS1IOHandlerImpl.hpp index 8e37d6872c..9344cc5e3b 100644 --- a/include/openPMD/IO/ADIOS/ParallelADIOS1IOHandlerImpl.hpp +++ b/include/openPMD/IO/ADIOS/ParallelADIOS1IOHandlerImpl.hpp @@ -103,7 +103,12 @@ class OPENPMDAPI_EXPORT ParallelADIOS1IOHandlerImpl m_openWriteFileHandles; std::unordered_map, ADIOS_FILE *> m_openReadFileHandles; - std::unordered_map > + struct ScheduledRead + { + ADIOS_SELECTION *selection; + std::shared_ptr data; // needed to avoid early freeing + }; + std::unordered_map > m_scheduledReads; std::unordered_map > m_attributeWrites; diff --git a/include/openPMD/backend/Attributable.hpp b/include/openPMD/backend/Attributable.hpp index 9ae989e090..f6e9800ed1 100644 --- a/include/openPMD/backend/Attributable.hpp +++ b/include/openPMD/backend/Attributable.hpp @@ -85,21 +85,37 @@ namespace internal A_MAP m_attributes; }; + enum class SetAttributeMode : char + { + WhileReadingAttributes, + FromPublicAPICall + }; + /** Verify values of attributes in the frontend * * verify string attributes are not empty (backend restriction, e.g., HDF5) */ template - inline void attr_value_check(std::string const /* key */, T /* value */) + inline void attr_value_check( + std::string const /* key */, T /* value */, SetAttributeMode) {} template <> - inline void attr_value_check(std::string const key, std::string const value) + inline void attr_value_check( + std::string const key, std::string const value, SetAttributeMode mode) { - if (value.empty()) - throw std::runtime_error( - "[setAttribute] Value for string attribute '" + key + - "' must not be empty!"); + switch (mode) + { + case SetAttributeMode::FromPublicAPICall: + if (value.empty()) + throw std::runtime_error( + "[setAttribute] Value for string attribute '" + key + + "' must not be empty!"); + break; + case SetAttributeMode::WhileReadingAttributes: + // no checks while reading + break; + } } } // namespace internal @@ -267,6 +283,13 @@ class AttributableInterface void seriesFlush(internal::FlushParams); void flushAttributes(internal::FlushParams const &); + + template + bool setAttributeImpl( + std::string const &key, T value, internal::SetAttributeMode); + bool setAttributeImpl( + std::string const &key, char const value[], internal::SetAttributeMode); + enum ReadMode { /** @@ -431,11 +454,29 @@ class LegacyAttributable : public AttributableInterface } }; -// TODO explicitly instantiate Attributable::setAttribute for all T in Datatype template inline bool AttributableInterface::setAttribute(std::string const &key, T value) { - internal::attr_value_check(key, value); + return setAttributeImpl( + key, std::move(value), internal::SetAttributeMode::FromPublicAPICall); +} + +inline bool +Attributable::setAttribute(std::string const &key, char const value[]) +{ + return setAttributeImpl( + key, value, internal::SetAttributeMode::FromPublicAPICall); +} + +// note: we explicitly instantiate Attributable::setAttributeImpl for all T in +// Datatype in Attributable.cpp +template +inline bool Attributable::setAttributeImpl( + std::string const &key, + T value, + internal::SetAttributeMode setAttributeMode) +{ + internal::attr_value_check(key, value, setAttributeMode); auto &attri = get(); if (IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess) @@ -468,10 +509,12 @@ inline bool AttributableInterface::setAttribute(std::string const &key, T value) } } -inline bool -AttributableInterface::setAttribute(std::string const &key, char const value[]) +inline bool Attributable::setAttributeImpl( + std::string const &key, + char const value[], + internal::SetAttributeMode setAttributeMode) { - return this->setAttribute(key, std::string(value)); + return this->setAttributeImpl(key, std::string(value), setAttributeMode); } template diff --git a/src/IO/ADIOS/ADIOS1IOHandler.cpp b/src/IO/ADIOS/ADIOS1IOHandler.cpp index cafe9f8750..f13808190b 100644 --- a/src/IO/ADIOS/ADIOS1IOHandler.cpp +++ b/src/IO/ADIOS/ADIOS1IOHandler.cpp @@ -296,7 +296,7 @@ std::future ADIOS1IOHandlerImpl::flush() "dataset reading"); for (auto &sel : file.second) - adios_selection_delete(sel); + adios_selection_delete(sel.selection); } m_scheduledReads.clear(); diff --git a/src/IO/ADIOS/CommonADIOS1IOHandler.cpp b/src/IO/ADIOS/CommonADIOS1IOHandler.cpp index 2df3bea460..3781e4070a 100644 --- a/src/IO/ADIOS/CommonADIOS1IOHandler.cpp +++ b/src/IO/ADIOS/CommonADIOS1IOHandler.cpp @@ -639,7 +639,7 @@ void CommonADIOS1IOHandlerImpl::closeFile( "dataset reading"); for (auto &sel : scheduled->second) - adios_selection_delete(sel); + adios_selection_delete(sel.selection); m_scheduledReads.erase(scheduled); } close(handle_read->second); @@ -1083,7 +1083,7 @@ void CommonADIOS1IOHandlerImpl::readDataset( "[ADIOS1] Internal error: Failed to schedule ADIOS read during dataset " "reading"); - m_scheduledReads[f].push_back(sel); + m_scheduledReads[f].push_back({sel, parameters.data}); } void CommonADIOS1IOHandlerImpl::readAttribute( diff --git a/src/IO/ADIOS/ParallelADIOS1IOHandler.cpp b/src/IO/ADIOS/ParallelADIOS1IOHandler.cpp index 722d25238c..75033ea520 100644 --- a/src/IO/ADIOS/ParallelADIOS1IOHandler.cpp +++ b/src/IO/ADIOS/ParallelADIOS1IOHandler.cpp @@ -320,7 +320,7 @@ std::future ParallelADIOS1IOHandlerImpl::flush() "dataset reading"); for (auto &sel : file.second) - adios_selection_delete(sel); + adios_selection_delete(sel.selection); } m_scheduledReads.clear(); diff --git a/src/IO/AbstractIOHandlerHelper.cpp b/src/IO/AbstractIOHandlerHelper.cpp index 31a659d8f7..e053372e40 100644 --- a/src/IO/AbstractIOHandlerHelper.cpp +++ b/src/IO/AbstractIOHandlerHelper.cpp @@ -29,8 +29,33 @@ #include "openPMD/IO/JSON/JSONIOHandler.hpp" #include "openPMD/auxiliary/JSON.hpp" +#include +#include + namespace openPMD { + +namespace +{ + template + std::shared_ptr + constructIOHandler(std::string const &backendName, Args &&...args) + { + if /* constexpr */ (enabled) + { + return std::make_shared(std::forward(args)...); + } + else + { + throw std::runtime_error( + "openPMD-api built without support for " + "backend '" + + backendName + "'."); + } + throw "Unreachable"; + } +} // namespace + #if openPMD_HAVE_MPI template <> std::shared_ptr createIOHandler( @@ -44,23 +69,24 @@ std::shared_ptr createIOHandler( switch (format) { case Format::HDF5: - return std::make_shared( - path, access, comm, std::move(options)); + return constructIOHandler( + "HDF5", path, access, comm, std::move(options)); case Format::ADIOS1: #if openPMD_HAVE_ADIOS1 - return std::make_shared(path, access, comm); + return constructIOHandler( + "ADIOS1", path, access, comm); #else throw std::runtime_error("openPMD-api built without ADIOS1 support"); #endif case Format::ADIOS2: - return std::make_shared( - path, access, comm, std::move(options), "bp4"); + return constructIOHandler( + "ADIOS2", path, access, comm, std::move(options), "bp4"); case Format::ADIOS2_SST: - return std::make_shared( - path, access, comm, std::move(options), "sst"); + return constructIOHandler( + "ADIOS2", path, access, comm, std::move(options), "sst"); case Format::ADIOS2_SSC: - return std::make_shared( - path, access, comm, std::move(options), "ssc"); + return constructIOHandler( + "ADIOS2", path, access, comm, std::move(options), "ssc"); default: throw std::runtime_error( "Unknown file format! Did you specify a file ending?"); @@ -76,27 +102,29 @@ std::shared_ptr createIOHandler( switch (format) { case Format::HDF5: - return std::make_shared( - path, access, std::move(options)); + return constructIOHandler( + "HDF5", path, access, std::move(options)); case Format::ADIOS1: #if openPMD_HAVE_ADIOS1 - return std::make_shared(path, access); + return constructIOHandler( + "ADIOS1", path, access); #else throw std::runtime_error("openPMD-api built without ADIOS1 support"); #endif #if openPMD_HAVE_ADIOS2 case Format::ADIOS2: - return std::make_shared( - path, access, std::move(options), "bp4"); + return constructIOHandler( + "ADIOS2", path, access, std::move(options), "bp4"); case Format::ADIOS2_SST: - return std::make_shared( - path, access, std::move(options), "sst"); + return constructIOHandler( + "ADIOS2", path, access, std::move(options), "sst"); case Format::ADIOS2_SSC: - return std::make_shared( - path, access, std::move(options), "ssc"); -#endif // openPMD_HAVE_ADIOS2 + return constructIOHandler( + "ADIOS2", path, access, std::move(options), "ssc"); +#endif case Format::JSON: - return std::make_shared(path, access); + return constructIOHandler( + "JSON", path, access); default: throw std::runtime_error( "Unknown file format! Did you specify a file ending?"); diff --git a/src/backend/Attributable.cpp b/src/backend/Attributable.cpp index 79bde3a9dc..9c3f737f9e 100644 --- a/src/backend/Attributable.cpp +++ b/src/backend/Attributable.cpp @@ -309,96 +309,183 @@ void AttributableInterface::readAttributes(ReadMode mode) } std::array arr; std::copy_n(vector.begin(), 7, arr.begin()); - setAttribute(key, std::move(arr)); + setAttributeImpl( + key, + std::move(arr), + internal::SetAttributeMode::WhileReadingAttributes); } else { - setAttribute(key, std::move(vector)); + setAttributeImpl( + key, + std::move(vector), + internal::SetAttributeMode::WhileReadingAttributes); } }; switch (*aRead.dtype) { case DT::CHAR: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::UCHAR: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::SHORT: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::INT: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::LONG: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::LONGLONG: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::USHORT: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::UINT: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::ULONG: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::ULONGLONG: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::FLOAT: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::DOUBLE: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::LONG_DOUBLE: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::CFLOAT: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::CDOUBLE: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::CLONG_DOUBLE: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::STRING: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_CHAR: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_SHORT: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_INT: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_LONG: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_LONGLONG: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_UCHAR: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_USHORT: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_UINT: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_ULONG: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_ULONGLONG: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_FLOAT: guardUnitDimension(att, a.get >()); @@ -410,23 +497,40 @@ void AttributableInterface::readAttributes(ReadMode mode) guardUnitDimension(att, a.get >()); break; case DT::VEC_CFLOAT: - setAttribute(att, a.get > >()); + setAttributeImpl( + att, + a.get > >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_CDOUBLE: - setAttribute(att, a.get > >()); + setAttributeImpl( + att, + a.get > >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_CLONG_DOUBLE: - setAttribute( - att, a.get > >()); + setAttributeImpl( + att, + a.get > >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::VEC_STRING: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::ARR_DBL_7: - setAttribute(att, a.get >()); + setAttributeImpl( + att, + a.get >(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::BOOL: - setAttribute(att, a.get()); + setAttributeImpl( + att, + a.get(), + internal::SetAttributeMode::WhileReadingAttributes); break; case DT::DATATYPE: case DT::UNDEFINED: diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp index 3958a1558b..0bf558b650 100644 --- a/test/SerialIOTest.cpp +++ b/test/SerialIOTest.cpp @@ -382,6 +382,15 @@ TEST_CASE("available_chunks_test_json", "[serial][json]") TEST_CASE("multiple_series_handles_test", "[serial]") { + /* + * clang also understands these pragmas. + */ +#if defined(__GNUC_MINOR__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__clang__) +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif /* * First test: No premature flushes through destructor when another copy * is still around @@ -424,6 +433,11 @@ TEST_CASE("multiple_series_handles_test", "[serial]") */ series_ptr->flush(); } +#if defined(__GNUC_MINOR__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#elif defined(__clang__) +#pragma clang diagnostic pop +#endif } void close_iteration_test(std::string file_ending)