From 1d802650454ac346f4bc5d15ecdb0fe852fb9b82 Mon Sep 17 00:00:00 2001 From: Jared Duffey Date: Tue, 23 Apr 2024 16:46:03 -0400 Subject: [PATCH] BUG: Fix HDF5 implicit copy crashes. (#924) Signed-off-by: Jared Duffey --- cmake/Utility.cmake | 7 + .../Utilities/Parsing/HDF5/IO/AttributeIO.cpp | 17 +- .../Utilities/Parsing/HDF5/IO/AttributeIO.hpp | 12 +- .../Utilities/Parsing/HDF5/IO/DatasetIO.cpp | 6 +- .../Utilities/Parsing/HDF5/IO/DatasetIO.hpp | 8 +- .../Utilities/Parsing/HDF5/IO/FileIO.cpp | 13 +- .../Utilities/Parsing/HDF5/IO/FileIO.hpp | 10 +- .../Utilities/Parsing/HDF5/IO/GroupIO.hpp | 8 +- .../Utilities/Parsing/HDF5/IO/ObjectIO.cpp | 15 + .../Utilities/Parsing/HDF5/IO/ObjectIO.hpp | 8 +- .../Parsing/HDF5/Readers/AttributeReader.cpp | 13 + .../Parsing/HDF5/Readers/AttributeReader.hpp | 10 +- .../Parsing/HDF5/Readers/DatasetReader.cpp | 6 +- .../Parsing/HDF5/Readers/DatasetReader.hpp | 8 +- .../Parsing/HDF5/Readers/FileReader.hpp | 8 +- .../Parsing/HDF5/Readers/GroupReader.hpp | 8 +- .../Parsing/HDF5/Readers/ObjectReader.cpp | 13 + .../Parsing/HDF5/Readers/ObjectReader.hpp | 8 +- .../Parsing/HDF5/Writers/AttributeWriter.cpp | 19 +- .../Parsing/HDF5/Writers/AttributeWriter.hpp | 14 +- .../Parsing/HDF5/Writers/DatasetWriter.cpp | 25 +- .../Parsing/HDF5/Writers/DatasetWriter.hpp | 12 +- .../Parsing/HDF5/Writers/FileWriter.cpp | 10 +- .../Parsing/HDF5/Writers/FileWriter.hpp | 10 +- .../Parsing/HDF5/Writers/GroupWriter.cpp | 7 +- .../Parsing/HDF5/Writers/GroupWriter.hpp | 8 +- .../Parsing/HDF5/Writers/ObjectWriter.cpp | 24 +- .../Parsing/HDF5/Writers/ObjectWriter.hpp | 17 +- test/H5Test.cpp | 387 +++++++++++++----- 29 files changed, 481 insertions(+), 230 deletions(-) diff --git a/cmake/Utility.cmake b/cmake/Utility.cmake index 6be4c26d2a..7c25abbe87 100644 --- a/cmake/Utility.cmake +++ b/cmake/Utility.cmake @@ -73,12 +73,19 @@ function(simplnx_enable_warnings) set(SHADOW_WARNING "shadow-all") endif() + if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CLANG_WARNINGS + -Werror=implicit-exception-spec-mismatch # Wimplicit-exception-spec-mismatch: function previously declared with an explicit/implicit exception specification redeclared with an implicit/explicit exception specification + ) + endif() + target_compile_options(${ARG_TARGET} PRIVATE # Warning to error -Werror=parentheses # Wparentheses: Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about -Werror=return-type # Wreturn-type: Warn about any "return" statement with no return value in a function whose return type is not "void" -Werror=${SHADOW_WARNING} # Wshadow: Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C) or whenever a built-in function is shadowed. + ${CLANG_WARNINGS} ) endif() diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.cpp b/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.cpp index 977534b837..1e413c30f1 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.cpp @@ -31,7 +31,22 @@ AttributeIO::AttributeIO(IdType objectId, const std::string& attrName) HDF_ERROR_HANDLER_ON } -AttributeIO::~AttributeIO() +AttributeIO::AttributeIO(AttributeIO&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeId = std::exchange(other.m_AttributeId, 0); + m_AttributeName = std::move(other.m_AttributeName); +} + +AttributeIO& AttributeIO::operator=(AttributeIO&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeId = std::exchange(other.m_AttributeId, 0); + m_AttributeName = std::move(other.m_AttributeName); + return *this; +} + +AttributeIO::~AttributeIO() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.hpp b/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.hpp index 5c9953561a..d686dcd9e3 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/AttributeIO.hpp @@ -38,12 +38,15 @@ class SIMPLNX_EXPORT AttributeIO AttributeIO(IdType objectId, const std::string& attrName); AttributeIO(const AttributeIO& other) = delete; - AttributeIO(AttributeIO&& other) noexcept = default; + AttributeIO(AttributeIO&& other) noexcept; + + AttributeIO& operator=(const AttributeIO& other) = delete; + AttributeIO& operator=(AttributeIO&& other) noexcept; /** * @brief Releases the wrapped HDF5 attribute. */ - virtual ~AttributeIO(); + ~AttributeIO() noexcept; /** * @brief Returns true if the AttributeIO has a valid target. @@ -167,9 +170,6 @@ class SIMPLNX_EXPORT AttributeIO template Result<> writeVector(const DimsVector& dims, const std::vector& vector); - AttributeIO& operator=(const AttributeIO& other) = delete; - AttributeIO& operator=(AttributeIO&& other) noexcept = delete; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. @@ -186,7 +186,7 @@ class SIMPLNX_EXPORT AttributeIO private: IdType m_ObjectId = 0; IdType m_AttributeId = 0; - const std::string m_AttributeName; + std::string m_AttributeName; }; extern template SIMPLNX_EXPORT int8_t AttributeIO::readAsValue() const; diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.cpp b/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.cpp index 82f2b0a16d..daf79134db 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.cpp @@ -12,9 +12,7 @@ namespace nx::core::HDF5 { -DatasetIO::DatasetIO() -{ -} +DatasetIO::DatasetIO() = default; DatasetIO::DatasetIO(IdType parentId, const std::string& datasetName) : ObjectIO(parentId) @@ -29,7 +27,7 @@ DatasetIO::DatasetIO(DatasetIO&& other) noexcept { } -DatasetIO::~DatasetIO() +DatasetIO::~DatasetIO() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.hpp b/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.hpp index 8ea2a454a2..34a2f1c938 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/DatasetIO.hpp @@ -38,10 +38,13 @@ class SIMPLNX_EXPORT DatasetIO : public ObjectIO DatasetIO(DatasetIO&& other) noexcept; + DatasetIO& operator=(const DatasetIO& rhs) = delete; + DatasetIO& operator=(DatasetIO&& rhs) noexcept; + /** * @brief Releases the HDF5 dataset. */ - virtual ~DatasetIO(); + ~DatasetIO() noexcept override; /** * @brief Returns true if the DatasetIO has a valid target. Otherwise, @@ -260,9 +263,6 @@ class SIMPLNX_EXPORT DatasetIO : public ObjectIO createOrOpenDataset(dimensions, properties); } - DatasetIO& operator=(const DatasetIO& rhs) = delete; - DatasetIO& operator=(DatasetIO&& rhs) noexcept; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.cpp b/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.cpp index 77b3eb462f..4670793e39 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.cpp @@ -115,10 +115,7 @@ hid_t createOrOpenFile(const std::filesystem::path& filepath) return H5Fcreate(filepath.string().c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); } -FileIO::FileIO() -: GroupIO() -{ -} +FileIO::FileIO() = default; FileIO::FileIO(const std::filesystem::path& filepath) : GroupIO(0, createOrOpenFile(filepath)) @@ -130,14 +127,6 @@ FileIO::FileIO(IdType fileId) { } -FileIO::FileIO(FileIO&& rhs) noexcept -: GroupIO() -{ - auto rhsId = rhs.getId(); - setId(rhsId); - rhs.setId(-1); -} - FileIO::~FileIO() noexcept { closeHdf5(); diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.hpp b/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.hpp index cd8402f6e9..814982e123 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/FileIO.hpp @@ -67,12 +67,15 @@ class SIMPLNX_EXPORT FileIO : public GroupIO * @brief Move constructor. * @param rhs */ - FileIO(FileIO&& rhs) noexcept; + FileIO(FileIO&& rhs) noexcept = default; + + FileIO& operator=(const FileIO& rhs) = delete; + FileIO& operator=(FileIO&& rhs) noexcept = default; /** * @brief Releases the HDF5 file ID. */ - virtual ~FileIO() noexcept; + ~FileIO() noexcept override; /** * @brief Returns the HDF5 file name. Returns an empty string if the file @@ -81,9 +84,6 @@ class SIMPLNX_EXPORT FileIO : public GroupIO */ std::string getName() const override; - FileIO& operator=(const FileIO& rhs) = delete; - FileIO& operator=(FileIO&& rhs) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/GroupIO.hpp b/src/simplnx/Utilities/Parsing/HDF5/IO/GroupIO.hpp index dfd7e5a581..ba600b2d94 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/GroupIO.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/GroupIO.hpp @@ -24,10 +24,13 @@ class SIMPLNX_EXPORT GroupIO : public ObjectIO GroupIO(const GroupIO& other) = delete; GroupIO(GroupIO&& other) noexcept = default; + GroupIO& operator=(const GroupIO& other) = delete; + GroupIO& operator=(GroupIO&& other) noexcept = default; + /** * @brief Releases the wrapped HDF5 group. */ - virtual ~GroupIO() noexcept; + ~GroupIO() noexcept override; /** * @brief Attempts to open a nested HDF5 group with the specified name. @@ -138,9 +141,6 @@ class SIMPLNX_EXPORT GroupIO : public ObjectIO */ bool isDataset(const std::string& childName) const; - GroupIO& operator=(const GroupIO& other) = delete; - GroupIO& operator=(GroupIO&& other) noexcept = default; - protected: /** * @brief Constructs a GroupWriter for use in derived classes. This diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.cpp b/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.cpp index 3cac67df33..f519a69300 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.cpp @@ -26,6 +26,21 @@ ObjectIO::ObjectIO(IdType parentId, const std::string& targetName) m_Id = H5Oopen(parentId, targetName.c_str(), H5P_DEFAULT); } +ObjectIO::ObjectIO(ObjectIO&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); + m_SharedParentPtr = std::move(other.m_SharedParentPtr); +} + +ObjectIO& ObjectIO::operator=(ObjectIO&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); + m_SharedParentPtr = std::move(other.m_SharedParentPtr); + return *this; +} + ObjectIO::~ObjectIO() noexcept { closeHdf5(); diff --git a/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.hpp b/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.hpp index 713a79e56c..683c6163ee 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/IO/ObjectIO.hpp @@ -27,7 +27,10 @@ class SIMPLNX_EXPORT ObjectIO ObjectIO(IdType parentId, const std::string& targetName); ObjectIO(const ObjectIO& other) = delete; - ObjectIO(ObjectIO&& other) noexcept = default; + ObjectIO(ObjectIO&& other) noexcept; + + ObjectIO& operator=(const ObjectIO& other) = delete; + ObjectIO& operator=(ObjectIO&& other) noexcept; /** * @brief Releases the wrapped HDF5 object. @@ -131,9 +134,6 @@ class SIMPLNX_EXPORT ObjectIO */ AttributeIO createAttribute(const std::string& name); - ObjectIO& operator=(const ObjectIO& other) = delete; - ObjectIO& operator=(ObjectIO&& other) noexcept = default; - protected: /** * @brief Constructs an ObjectIO for use in derived classes. This diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.cpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.cpp index 8450ea0dd8..8920803355 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.cpp @@ -26,6 +26,19 @@ AttributeReader::AttributeReader(IdType objectId, const std::string& attrName) HDF_ERROR_HANDLER_ON } +AttributeReader::AttributeReader(AttributeReader&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeId = std::exchange(other.m_AttributeId, 0); +} + +AttributeReader& AttributeReader::operator=(AttributeReader&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeId = std::exchange(other.m_AttributeId, 0); + return *this; +} + AttributeReader::~AttributeReader() noexcept { closeHdf5(); diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.hpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.hpp index 1b16287871..3b4157ea55 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/AttributeReader.hpp @@ -37,12 +37,15 @@ class SIMPLNX_EXPORT AttributeReader AttributeReader(IdType objectId, const std::string& attrName); AttributeReader(const AttributeReader& other) = delete; - AttributeReader(AttributeReader&& other) noexcept = default; + AttributeReader(AttributeReader&& other) noexcept; + + AttributeReader& operator=(const AttributeReader& other) = delete; + AttributeReader& operator=(AttributeReader&& other) noexcept; /** * @brief Releases the wrapped HDF5 attribute. */ - virtual ~AttributeReader() noexcept; + ~AttributeReader() noexcept; /** * @brief Returns true if the AttributeReader has a valid target. @@ -149,9 +152,6 @@ class SIMPLNX_EXPORT AttributeReader */ std::string readAsString() const; - AttributeReader& operator=(const AttributeReader& other) = delete; - AttributeReader& operator=(AttributeReader&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.cpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.cpp index 236e34fd31..f2497e77a5 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.cpp @@ -10,16 +10,14 @@ namespace nx::core::HDF5 { -DatasetReader::DatasetReader() -{ -} +DatasetReader::DatasetReader() = default; DatasetReader::DatasetReader(IdType parentId, const std::string& dataName) : ObjectReader(parentId, H5Dopen(parentId, dataName.c_str(), H5P_DEFAULT)) { } -DatasetReader::~DatasetReader() +DatasetReader::~DatasetReader() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.hpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.hpp index 53e2e2905b..3a91f4190c 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/DatasetReader.hpp @@ -30,10 +30,13 @@ class SIMPLNX_EXPORT DatasetReader : public ObjectReader DatasetReader(const DatasetReader& other) = delete; DatasetReader(DatasetReader&& other) noexcept = default; + DatasetReader& operator=(const DatasetReader& other) = delete; + DatasetReader& operator=(DatasetReader&& other) noexcept = default; + /** * @brief Releases the HDF5 dataset. */ - virtual ~DatasetReader(); + ~DatasetReader() noexcept override; /** * @brief Returns the dataspace's HDF5 ID. Returns 0 if the attribute is @@ -125,9 +128,6 @@ class SIMPLNX_EXPORT DatasetReader : public ObjectReader std::string getFilterName() const; - DatasetReader& operator=(const DatasetReader& other) = delete; - DatasetReader& operator=(DatasetReader&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp index 2b2c13b029..dd9d5e8c44 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp @@ -29,10 +29,13 @@ class SIMPLNX_EXPORT FileReader : public GroupReader FileReader(const FileReader& other) = delete; FileReader(FileReader&& other) noexcept = default; + FileReader& operator=(const FileReader& other) = delete; + FileReader& operator=(FileReader&& other) noexcept = default; + /** * @brief Releases the HDF5 file ID. */ - virtual ~FileReader() noexcept; + ~FileReader() noexcept override; /** * @brief Returns the HDF5 file name. Returns an empty string if the file @@ -41,9 +44,6 @@ class SIMPLNX_EXPORT FileReader : public GroupReader */ std::string getName() const override; - FileReader& operator=(const FileReader& other) = delete; - FileReader& operator=(FileReader&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/GroupReader.hpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/GroupReader.hpp index 9d1e5e0804..ad2ca0b9b9 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/GroupReader.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/GroupReader.hpp @@ -22,10 +22,13 @@ class SIMPLNX_EXPORT GroupReader : public ObjectReader GroupReader(const GroupReader& other) = delete; GroupReader(GroupReader&& other) noexcept = default; + GroupReader& operator=(const GroupReader& other) = delete; + GroupReader& operator=(GroupReader&& other) noexcept = default; + /** * @brief Releases the wrapped HDF5 group. */ - virtual ~GroupReader() noexcept; + ~GroupReader() noexcept override; /** * @brief Attempts to open a nested HDF5 group with the specified name. @@ -90,9 +93,6 @@ class SIMPLNX_EXPORT GroupReader : public ObjectReader */ bool isDataset(const std::string& childName) const; - GroupReader& operator=(const GroupReader& other) = delete; - GroupReader& operator=(GroupReader&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.cpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.cpp index 19b0d4479a..cacfdcb515 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.cpp @@ -25,6 +25,19 @@ ObjectReader::ObjectReader(IdType parentId, const std::string& targetName) m_Id = H5Oopen(parentId, targetName.c_str(), H5P_DEFAULT); } +ObjectReader::ObjectReader(ObjectReader&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); +} + +ObjectReader& ObjectReader::operator=(ObjectReader&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); + return *this; +} + ObjectReader::~ObjectReader() noexcept { closeHdf5(); diff --git a/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.hpp b/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.hpp index e5996e76f2..0271bda1b6 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Readers/ObjectReader.hpp @@ -25,7 +25,10 @@ class SIMPLNX_EXPORT ObjectReader ObjectReader(IdType parentId, const std::string& targetName); ObjectReader(const ObjectReader& other) = delete; - ObjectReader(ObjectReader&& other) noexcept = default; + ObjectReader(ObjectReader&& other) noexcept; + + ObjectReader& operator=(const ObjectReader& other) = delete; + ObjectReader& operator=(ObjectReader&& other) noexcept; /** * @brief Releases the wrapped HDF5 object. @@ -99,9 +102,6 @@ class SIMPLNX_EXPORT ObjectReader */ AttributeReader getAttributeByIdx(size_t idx) const; - ObjectReader& operator=(const ObjectReader& other) = delete; - ObjectReader& operator=(ObjectReader&& other) noexcept = default; - protected: /** * @brief Constructs an ObjectReader for use in derived classes. This diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.cpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.cpp index 930fb1beb1..df2bb0d24c 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.cpp @@ -11,9 +11,7 @@ namespace nx::core::HDF5 { -AttributeWriter::AttributeWriter() -{ -} +AttributeWriter::AttributeWriter() = default; AttributeWriter::AttributeWriter(IdType objectId, const std::string& attributeName) : m_ObjectId(objectId) @@ -21,7 +19,20 @@ AttributeWriter::AttributeWriter(IdType objectId, const std::string& attributeNa { } -AttributeWriter::~AttributeWriter() = default; +AttributeWriter::AttributeWriter(AttributeWriter&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeName = std::move(other.m_AttributeName); +} + +AttributeWriter& AttributeWriter::operator=(AttributeWriter&& other) noexcept +{ + m_ObjectId = std::exchange(other.m_ObjectId, 0); + m_AttributeName = std::move(other.m_AttributeName); + return *this; +} + +AttributeWriter::~AttributeWriter() noexcept = default; nx::core::Result<> AttributeWriter::findAndDeleteAttribute() { diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.hpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.hpp index 062aa261e8..d1c17c75da 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/AttributeWriter.hpp @@ -32,12 +32,15 @@ class SIMPLNX_EXPORT AttributeWriter AttributeWriter(IdType objectId, const std::string& attributeName); AttributeWriter(const AttributeWriter& other) = delete; - AttributeWriter(AttributeWriter&& other) noexcept = default; + AttributeWriter(AttributeWriter&& other) noexcept; + + AttributeWriter& operator=(const AttributeWriter& other) = delete; + AttributeWriter& operator=(AttributeWriter&& other) noexcept; /** * @brief Default destructor */ - virtual ~AttributeWriter(); + ~AttributeWriter() noexcept; /** * @brief Returns true if the AttributeReader has a valid target. @@ -207,9 +210,6 @@ class SIMPLNX_EXPORT AttributeWriter return returnError; } - AttributeWriter& operator=(const AttributeWriter& other) = delete; - AttributeWriter& operator=(AttributeWriter&& other) noexcept = delete; - protected: /** * @brief Finds and deletes any existing attribute with the current name. @@ -219,7 +219,7 @@ class SIMPLNX_EXPORT AttributeWriter Result<> findAndDeleteAttribute(); private: - const IdType m_ObjectId = 0; - const std::string m_AttributeName; + IdType m_ObjectId = 0; + std::string m_AttributeName; }; } // namespace nx::core::HDF5 diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.cpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.cpp index 8d57584c5c..129b7eb1a4 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.cpp @@ -10,10 +10,7 @@ namespace nx::core::HDF5 { -DatasetWriter::DatasetWriter() -: ObjectWriter() -{ -} +DatasetWriter::DatasetWriter() = default; DatasetWriter::DatasetWriter(IdType parentId, const std::string& datasetName) : ObjectWriter(parentId) @@ -27,7 +24,25 @@ DatasetWriter::DatasetWriter(IdType parentId, const std::string& datasetName) #endif } -DatasetWriter::~DatasetWriter() +DatasetWriter::DatasetWriter(DatasetWriter&& other) noexcept +: ObjectWriter(std::move(other)) +, m_DatasetName(std::move(other.m_DatasetName)) +{ +} + +DatasetWriter& DatasetWriter::operator=(DatasetWriter&& other) noexcept +{ + setParentId(other.getParentId()); + setId(other.getId()); + m_DatasetName = std::move(other.m_DatasetName); + + other.setId(0); + other.setParentId(0); + + return *this; +} + +DatasetWriter::~DatasetWriter() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.hpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.hpp index 13190916cc..93c6c21677 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/DatasetWriter.hpp @@ -29,12 +29,15 @@ class SIMPLNX_EXPORT DatasetWriter : public ObjectWriter DatasetWriter(IdType parentId, const std::string& datasetName); DatasetWriter(const DatasetWriter& other) = delete; - DatasetWriter(DatasetWriter&& other) noexcept = default; + DatasetWriter(DatasetWriter&& other) noexcept; + + DatasetWriter& operator=(const DatasetWriter& other) = delete; + DatasetWriter& operator=(DatasetWriter&& other) noexcept; /** * @brief Default destructor */ - virtual ~DatasetWriter(); + ~DatasetWriter() noexcept override; /** * @brief Returns true if the DatasetWriter has a valid target. Otherwise, @@ -206,9 +209,6 @@ class SIMPLNX_EXPORT DatasetWriter : public ObjectWriter */ IdType getPListId() const; - DatasetWriter& operator=(const DatasetWriter& other) = delete; - DatasetWriter& operator=(DatasetWriter&& other) noexcept = delete; - protected: /** * @brief Finds and deletes any existing attribute with the current name. @@ -248,6 +248,6 @@ class SIMPLNX_EXPORT DatasetWriter : public ObjectWriter void closeHdf5() override; private: - const std::string m_DatasetName; + std::string m_DatasetName; }; } // namespace nx::core::HDF5 diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.cpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.cpp index 3d2cf1947b..36bbe9ed99 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.cpp @@ -51,14 +51,6 @@ Result FileWriter::WrapHdf5FileId(IdType fileId) FileWriter::FileWriter() = default; -FileWriter::FileWriter(FileWriter&& rhs) noexcept -: GroupWriter() -{ - auto rhsId = rhs.getId(); - setId(rhsId); - rhs.setId(-1); -} - FileWriter::FileWriter(const std::filesystem::path& filepath) : GroupWriter(0, H5Fcreate(filepath.string().c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) { @@ -75,7 +67,7 @@ FileWriter::FileWriter(IdType fileId) { } -FileWriter::~FileWriter() +FileWriter::~FileWriter() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.hpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.hpp index 87e317b8d3..d0c5e82c6f 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.hpp @@ -46,12 +46,15 @@ class SIMPLNX_EXPORT FileWriter : public GroupWriter * @brief Move constructor. * @param rhs */ - FileWriter(FileWriter&& rhs) noexcept; + FileWriter(FileWriter&& rhs) noexcept = default; + + FileWriter& operator=(const FileWriter& rhs) = delete; + FileWriter& operator=(FileWriter&& rhs) noexcept = default; /** * @brief Closes the HDF5 file. */ - ~FileWriter() override; + ~FileWriter() noexcept override; /** * @brief Returns the HDF5 file name. Returns an empty string if the writer @@ -60,9 +63,6 @@ class SIMPLNX_EXPORT FileWriter : public GroupWriter */ std::string getName() const override; - FileWriter& operator=(const FileWriter& rhs) = delete; - FileWriter& operator=(FileWriter&& rhs) noexcept = default; - protected: /** * @brief Constructs a FileWriter that creates and wraps an HDF5 file at the diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.cpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.cpp index 167a734a3d..ab55d987f8 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.cpp @@ -8,10 +8,7 @@ namespace nx::core::HDF5 { -GroupWriter::GroupWriter() -: ObjectWriter() -{ -} +GroupWriter::GroupWriter() = default; GroupWriter::GroupWriter(IdType parentId, IdType objectId) : ObjectWriter(parentId, objectId) @@ -36,7 +33,7 @@ GroupWriter::GroupWriter(IdType parentId, const std::string& groupName) } } -GroupWriter::~GroupWriter() +GroupWriter::~GroupWriter() noexcept { closeHdf5(); } diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.hpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.hpp index b83129b7d5..1eb9903877 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/GroupWriter.hpp @@ -27,10 +27,13 @@ class SIMPLNX_EXPORT GroupWriter : public ObjectWriter GroupWriter(const GroupWriter& other) = delete; GroupWriter(GroupWriter&& other) noexcept = default; + GroupWriter& operator=(const GroupWriter& other) = delete; + GroupWriter& operator=(GroupWriter&& other) noexcept = default; + /** * @brief Closes the HDF5 group. */ - virtual ~GroupWriter(); + ~GroupWriter() noexcept override; /** * @brief Returns true if the GroupWriter is valid. Returns false otherwise. @@ -65,9 +68,6 @@ class SIMPLNX_EXPORT GroupWriter : public ObjectWriter */ Result<> createLink(const std::string& objectPath); - GroupWriter& operator=(const GroupWriter& other) = delete; - GroupWriter& operator=(GroupWriter&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.cpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.cpp index 5490be077b..3fff59741a 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.cpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.cpp @@ -7,9 +7,7 @@ namespace nx::core::HDF5 { -ObjectWriter::ObjectWriter() -{ -} +ObjectWriter::ObjectWriter() = default; ObjectWriter::ObjectWriter(IdType parentId, IdType objectId) : m_ParentId(parentId) @@ -17,7 +15,20 @@ ObjectWriter::ObjectWriter(IdType parentId, IdType objectId) { } -ObjectWriter::~ObjectWriter() = default; +ObjectWriter::ObjectWriter(ObjectWriter&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); +} + +ObjectWriter& ObjectWriter::operator=(ObjectWriter&& other) noexcept +{ + m_Id = std::exchange(other.m_Id, 0); + m_ParentId = std::exchange(other.m_ParentId, 0); + return *this; +} + +ObjectWriter::~ObjectWriter() noexcept = default; IdType ObjectWriter::getFileId() const { @@ -29,6 +40,11 @@ IdType ObjectWriter::getFileId() const return H5Iget_file_id(getParentId()); } +void ObjectWriter::setParentId(IdType parentId) +{ + m_ParentId = parentId; +} + IdType ObjectWriter::getParentId() const { return m_ParentId; diff --git a/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.hpp b/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.hpp index c1dcbf4fc4..d284b4cce9 100644 --- a/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.hpp +++ b/src/simplnx/Utilities/Parsing/HDF5/Writers/ObjectWriter.hpp @@ -26,12 +26,15 @@ class SIMPLNX_EXPORT ObjectWriter ObjectWriter(IdType parentId, IdType objectId = 0); ObjectWriter(const ObjectWriter& other) = delete; - ObjectWriter(ObjectWriter&& other) noexcept = default; + ObjectWriter(ObjectWriter&& other) noexcept; + + ObjectWriter& operator=(const ObjectWriter& other) = delete; + ObjectWriter& operator=(ObjectWriter&& other) noexcept; /** * @brief Releases the wrapped HDF5 object. */ - virtual ~ObjectWriter(); + virtual ~ObjectWriter() noexcept; /** * @brief Returns true if the ObjectWriter has a valid target. Otherwise, @@ -93,15 +96,19 @@ class SIMPLNX_EXPORT ObjectWriter */ AttributeWriter createAttribute(const std::string& name); - ObjectWriter& operator=(const ObjectWriter& other) = delete; - ObjectWriter& operator=(ObjectWriter&& other) noexcept = default; - protected: /** * @brief Closes the HDF5 ID and resets it to 0. */ virtual void closeHdf5() = 0; + /** + * @brief Sets a new parent ID. + * This method should only be used in the move operations of derived classes. + * @param parentId + */ + void setParentId(IdType parentId); + private: IdType m_ParentId = 0; IdType m_Id = 0; diff --git a/test/H5Test.cpp b/test/H5Test.cpp index 0342a7b48e..8e2362a9fe 100644 --- a/test/H5Test.cpp +++ b/test/H5Test.cpp @@ -19,6 +19,7 @@ #include "simplnx/UnitTest/UnitTestCommon.hpp" #include "simplnx/Utilities/DataArrayUtilities.hpp" #include "simplnx/Utilities/Parsing/DREAM3D/Dream3dIO.hpp" +#include "simplnx/Utilities/Parsing/HDF5/IO/FileIO.hpp" #include "simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp" #include "simplnx/Utilities/Parsing/HDF5/Writers/FileWriter.hpp" #include "simplnx/Utilities/Parsing/Text/CsvParser.hpp" @@ -80,50 +81,6 @@ bool equalsf(const FloatVec3& lhs, const FloatVec3& rhs) } return true; } -} // namespace - -#if TEST_LEGACY -TEST_CASE("Read Legacy DREAM.3D Data") -{ - auto app = Application::GetOrCreateInstance(); - std::filesystem::path filepath = GetLegacyFilepath(); - REQUIRE(exists(filepath)); - Result result = DREAM3D::ImportDataStructureFromFile(filepath, true); - SIMPLNX_RESULT_REQUIRE_VALID(result); - DataStructure dataStructure = result.value(); - - const std::string geomName = "Small IN100"; - const auto* image = dataStructure.getDataAs(DataPath({geomName})); - REQUIRE(image != nullptr); - REQUIRE(equalsf(image->getOrigin(), FloatVec3(-47.0f, 0.0f, -29.0f))); - REQUIRE(image->getDimensions() == SizeVec3(189, 201, 117)); - REQUIRE(equalsf(image->getSpacing(), FloatVec3(0.25f, 0.25f, 0.25f))); - - { - const std::string testDCName = "DataContainer"; - DataPath testDCPath({testDCName}); - auto* testDC = dataStructure.getDataAs(testDCPath); - REQUIRE(testDC != nullptr); - - DataPath testAMPath = testDCPath.createChildPath("AttributeMatrix"); - REQUIRE(dataStructure.getDataAs(DataPath({testAMPath})) != nullptr); - - REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Int8")) != nullptr); - REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("UInt8")) != nullptr); - REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Float32")) != nullptr); - REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Float64")) != nullptr); - REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Bool")) != nullptr); - } - - { - DataPath grainDataPath({geomName, "Grain Data"}); - REQUIRE(dataStructure.getData(grainDataPath) != nullptr); - REQUIRE(dataStructure.getDataAs>(grainDataPath.createChildPath("NeighborList")) != nullptr); - REQUIRE(dataStructure.getDataAs(grainDataPath.createChildPath("NumElements")) != nullptr); - REQUIRE(dataStructure.getDataAs(grainDataPath.createChildPath("NumNeighbors")) != nullptr); - } -} -#endif DataStructure GetTestDataStructure() { @@ -131,10 +88,7 @@ DataStructure GetTestDataStructure() auto group = DataGroup::Create(dataStructure, "Group"); REQUIRE(group != nullptr); - auto montage = GridMontage::Create(dataStructure, "Montage", group->getId()); - REQUIRE(montage != nullptr); - - auto geom = ImageGeom::Create(dataStructure, "Geometry", montage->getId()); + auto geom = ImageGeom::Create(dataStructure, "Geometry"); REQUIRE(geom != nullptr); auto scalar = ScalarData::Create(dataStructure, "Scalar", 7, geom->getId()); @@ -197,69 +151,6 @@ DataStructure CreateDataStructure() return dataStructure; } -TEST_CASE("ImageGeometryIO") -{ - fs::path dataDir = GetDataDir(); - - if(!fs::exists(dataDir)) - { - REQUIRE(fs::create_directories(dataDir)); - } - - const DataPath imageGeomPath({"ImageGeom"}); - const std::string cellDataName = "CellData"; - const DataPath cellDataPath = imageGeomPath.createChildPath(cellDataName); - const CreateImageGeometryAction::DimensionType dims = {10, 10, 10}; - const CreateImageGeometryAction::OriginType origin = {0.0f, 0.0f, 0.0f}; - const CreateImageGeometryAction::SpacingType spacing = {1.0f, 1.0f, 1.0f}; - - DataStructure originalDataStructure; - auto action = CreateImageGeometryAction(imageGeomPath, dims, origin, spacing, cellDataName, IGeometry::LengthUnit::Micrometer); - Result<> actionResult = action.apply(originalDataStructure, IDataAction::Mode::Execute); - SIMPLNX_RESULT_REQUIRE_VALID(actionResult); - - fs::path filePath = dataDir / "ImageGeometryIO.dream3d"; - - std::string filePathString = filePath.string(); - - { - Result result = nx::core::HDF5::FileWriter::CreateFile(filePathString); - SIMPLNX_RESULT_REQUIRE_VALID(result); - - nx::core::HDF5::FileWriter fileWriter = std::move(result.value()); - REQUIRE(fileWriter.isValid()); - - Result<> writeResult = HDF5::DataStructureWriter::WriteFile(originalDataStructure, fileWriter); - SIMPLNX_RESULT_REQUIRE_VALID(writeResult); - } - - { - nx::core::HDF5::FileReader fileReader(filePathString); - REQUIRE(fileReader.isValid()); - - auto readResult = HDF5::DataStructureReader::ReadFile(fileReader); - SIMPLNX_RESULT_REQUIRE_VALID(readResult); - DataStructure newDataStructure = std::move(readResult.value()); - - auto* imageGeom = newDataStructure.getDataAs(imageGeomPath); - REQUIRE(imageGeom != nullptr); - - REQUIRE(imageGeom->getDimensions() == SizeVec3(dims)); - REQUIRE(imageGeom->getOrigin() == FloatVec3(origin)); - REQUIRE(imageGeom->getSpacing() == FloatVec3(spacing)); - - auto* cellData = imageGeom->getCellData(); - REQUIRE(cellData != nullptr); - - REQUIRE(cellData->getName() == cellDataName); - REQUIRE(imageGeom->getCellDataPath() == cellDataPath); - - auto cellDataShape = std::vector(dims.crbegin(), dims.crend()); - - REQUIRE(cellData->getShape() == cellDataShape); - } -} - const std::string k_TriangleGroupName = "TRIANGLE_GEOMETRY"; const std::string k_TriangleFaceName = "SharedTriList"; const std::string k_VertexListName = "SharedVertexList"; @@ -564,6 +455,170 @@ void checkNodeGeomData(const DataStructure& dataStructure, const NodeBasedGeomDa REQUIRE(newNodeData == nodeData); } +template +HDF5::IdType GetId(const T& object) +{ + if constexpr(std::is_same_v || std::is_same_v) + { + return object.getAttributeId(); + } + else if constexpr(std::is_same_v) + { + return object.getObjectId(); + } + else + { + return object.getId(); + } +} + +template +H5ClassT CreateTempObject() +{ + if constexpr(std::is_same_v) + { + return HDF5::FileReader(0); + } + else + { + return H5ClassT(); + } +} + +template +H5ClassT TestH5ImplicitCopy(H5ClassT&& originalObject, std::string_view testedClassName) +{ + INFO(testedClassName) + + REQUIRE(originalObject.isValid()); + + HDF5::IdType originalId = GetId(originalObject); + + H5ClassT moveConstructorObject(std::move(originalObject)); + + REQUIRE_FALSE(originalObject.isValid()); + REQUIRE(GetId(originalObject) != originalId); + REQUIRE(moveConstructorObject.isValid()); + REQUIRE(GetId(moveConstructorObject) == originalId); + + H5ClassT moveOperatorObject = CreateTempObject(); + moveOperatorObject = std::move(moveConstructorObject); + + REQUIRE_FALSE(moveConstructorObject.isValid()); + REQUIRE(GetId(moveConstructorObject) != originalId); + REQUIRE(moveOperatorObject.isValid()); + REQUIRE(GetId(moveOperatorObject) == originalId); + + return moveOperatorObject; +} +} // namespace + +#if TEST_LEGACY +TEST_CASE("Read Legacy DREAM.3D Data") +{ + auto app = Application::GetOrCreateInstance(); + std::filesystem::path filepath = GetLegacyFilepath(); + REQUIRE(exists(filepath)); + Result result = DREAM3D::ImportDataStructureFromFile(filepath, true); + SIMPLNX_RESULT_REQUIRE_VALID(result); + DataStructure dataStructure = result.value(); + + const std::string geomName = "Small IN100"; + const auto* image = dataStructure.getDataAs(DataPath({geomName})); + REQUIRE(image != nullptr); + REQUIRE(equalsf(image->getOrigin(), FloatVec3(-47.0f, 0.0f, -29.0f))); + REQUIRE(image->getDimensions() == SizeVec3(189, 201, 117)); + REQUIRE(equalsf(image->getSpacing(), FloatVec3(0.25f, 0.25f, 0.25f))); + + { + const std::string testDCName = "DataContainer"; + DataPath testDCPath({testDCName}); + auto* testDC = dataStructure.getDataAs(testDCPath); + REQUIRE(testDC != nullptr); + + DataPath testAMPath = testDCPath.createChildPath("AttributeMatrix"); + REQUIRE(dataStructure.getDataAs(DataPath({testAMPath})) != nullptr); + + REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Int8")) != nullptr); + REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("UInt8")) != nullptr); + REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Float32")) != nullptr); + REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Float64")) != nullptr); + REQUIRE(dataStructure.getDataAs(testAMPath.createChildPath("Bool")) != nullptr); + } + + { + DataPath grainDataPath({geomName, "Grain Data"}); + REQUIRE(dataStructure.getData(grainDataPath) != nullptr); + REQUIRE(dataStructure.getDataAs>(grainDataPath.createChildPath("NeighborList")) != nullptr); + REQUIRE(dataStructure.getDataAs(grainDataPath.createChildPath("NumElements")) != nullptr); + REQUIRE(dataStructure.getDataAs(grainDataPath.createChildPath("NumNeighbors")) != nullptr); + } +} +#endif + +TEST_CASE("ImageGeometryIO") +{ + fs::path dataDir = GetDataDir(); + + if(!fs::exists(dataDir)) + { + REQUIRE(fs::create_directories(dataDir)); + } + + const DataPath imageGeomPath({"ImageGeom"}); + const std::string cellDataName = "CellData"; + const DataPath cellDataPath = imageGeomPath.createChildPath(cellDataName); + const CreateImageGeometryAction::DimensionType dims = {10, 10, 10}; + const CreateImageGeometryAction::OriginType origin = {0.0f, 0.0f, 0.0f}; + const CreateImageGeometryAction::SpacingType spacing = {1.0f, 1.0f, 1.0f}; + + DataStructure originalDataStructure; + auto action = CreateImageGeometryAction(imageGeomPath, dims, origin, spacing, cellDataName, IGeometry::LengthUnit::Micrometer); + Result<> actionResult = action.apply(originalDataStructure, IDataAction::Mode::Execute); + SIMPLNX_RESULT_REQUIRE_VALID(actionResult); + + fs::path filePath = dataDir / "ImageGeometryIO.dream3d"; + + std::string filePathString = filePath.string(); + + { + Result result = nx::core::HDF5::FileWriter::CreateFile(filePathString); + SIMPLNX_RESULT_REQUIRE_VALID(result); + + nx::core::HDF5::FileWriter fileWriter = std::move(result.value()); + REQUIRE(fileWriter.isValid()); + + Result<> writeResult = HDF5::DataStructureWriter::WriteFile(originalDataStructure, fileWriter); + SIMPLNX_RESULT_REQUIRE_VALID(writeResult); + } + + { + nx::core::HDF5::FileReader fileReader(filePathString); + REQUIRE(fileReader.isValid()); + + auto readResult = HDF5::DataStructureReader::ReadFile(fileReader); + SIMPLNX_RESULT_REQUIRE_VALID(readResult); + DataStructure newDataStructure = std::move(readResult.value()); + + auto* imageGeom = newDataStructure.getDataAs(imageGeomPath); + REQUIRE(imageGeom != nullptr); + + REQUIRE(imageGeom->getDimensions() == SizeVec3(dims)); + REQUIRE(imageGeom->getOrigin() == FloatVec3(origin)); + REQUIRE(imageGeom->getSpacing() == FloatVec3(spacing)); + + auto* cellData = imageGeom->getCellData(); + REQUIRE(cellData != nullptr); + + REQUIRE(cellData->getName() == cellDataName); + REQUIRE(imageGeom->getCellDataPath() == cellDataPath); + + auto cellDataShape = std::vector(dims.crbegin(), dims.crend()); + + REQUIRE(cellData->getShape() == cellDataShape); + } +} + TEST_CASE("Node Based Geometry IO") { auto app = Application::GetOrCreateInstance(); @@ -799,3 +854,113 @@ TEST_CASE("H5 Utilities") objectName = nx::core::HDF5::GetNameFromBuffer("/Data"); REQUIRE(objectName == "Data"); } + +TEST_CASE("HDF5ImplicitCopyReaderTest") +{ + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + fs::path filePath = GetDataDir() / "HDF5ImplicitCopyReaderTest.dream3d"; + { + DataStructure dataStructure = GetTestDataStructure(); + + Result<> writeFileResult = DREAM3D::WriteFile(filePath, dataStructure); + SIMPLNX_RESULT_REQUIRE_VALID(writeFileResult); + } + HDF5::FileReader fileReader(filePath); + HDF5::FileReader newFileReader = TestH5ImplicitCopy(std::move(fileReader), "HDF5::FileReader"); + + HDF5::GroupReader groupReader = newFileReader.openGroup("DataStructure"); + HDF5::GroupReader newGroupReader = TestH5ImplicitCopy(std::move(groupReader), "HDF5::GroupReader"); + + HDF5::GroupReader groupReaderIntermediate = newGroupReader.openGroup("Geometry"); + REQUIRE(groupReaderIntermediate.isValid()); + + HDF5::DatasetReader datasetReader = groupReaderIntermediate.openDataset("DataArray"); + TestH5ImplicitCopy(std::move(datasetReader), "HDF5::DatasetReader"); + + HDF5::ObjectReader objectReader = groupReaderIntermediate.openObject("Scalar"); + TestH5ImplicitCopy(std::move(objectReader), "HDF5::ObjectReader"); + + HDF5::AttributeReader originalAttributeReader = newFileReader.getAttribute("FileVersion"); + TestH5ImplicitCopy(std::move(originalAttributeReader), "HDF5::AttributeReader"); +} + +TEST_CASE("HDF5ImplicitCopyWriterTest") +{ + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + + fs::path outputPath = GetDataDir() / "HDF5ImplicitCopyWriterTest.h5"; + fs::remove(outputPath); + + auto fileWriterResult = HDF5::FileWriter::CreateFile(outputPath); + SIMPLNX_RESULT_REQUIRE_VALID(fileWriterResult); + + HDF5::FileWriter fileWriter = std::move(fileWriterResult.value()); + HDF5::FileWriter newFileWriter = TestH5ImplicitCopy(std::move(fileWriter), "HDF5::FileWriter"); + + HDF5::GroupWriter groupWriter = newFileWriter.createGroupWriter("foo"); + TestH5ImplicitCopy(std::move(groupWriter), "HDF5::GroupWriter"); + + HDF5::DatasetWriter datasetWriter = newFileWriter.createDatasetWriter("bar"); + REQUIRE(datasetWriter.isValid()); + std::array data = {1, 2, 3, 4, 5}; + HDF5::DatasetWriter::DimsType dims = {data.size()}; + Result<> datasetResult = datasetWriter.writeSpan(dims, nonstd::span(data)); + SIMPLNX_RESULT_REQUIRE_VALID(datasetResult); + TestH5ImplicitCopy(std::move(datasetWriter), "HDF5::DatasetWriter"); + + HDF5::AttributeWriter attributeWriter = newFileWriter.createAttribute("baz"); + TestH5ImplicitCopy(std::move(attributeWriter), "HDF5::AttributeWriter"); +} + +TEST_CASE("HDF5ImplicitCopyIOTest") +{ + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + STATIC_REQUIRE_FALSE(std::is_copy_assignable_v); + + fs::path filePath = GetDataDir() / "HDF5ImplicitCopyIOTest.dream3d"; + { + DataStructure dataStructure = GetTestDataStructure(); + + Result<> writeFileResult = DREAM3D::WriteFile(filePath, dataStructure); + SIMPLNX_RESULT_REQUIRE_VALID(writeFileResult); + } + + auto fileIOResult = HDF5::FileIO::CreateFile(filePath); + SIMPLNX_RESULT_REQUIRE_VALID(fileIOResult); + + HDF5::FileIO fileIO = std::move(fileIOResult.value()); + HDF5::FileIO newFileIO = TestH5ImplicitCopy(std::move(fileIO), "HDF5::FileIO"); + + HDF5::GroupIO groupIO = newFileIO.createGroup("DataStructure"); + HDF5::GroupIO newGroupIO = TestH5ImplicitCopy(std::move(groupIO), "HDF5::GroupIO"); + + HDF5::GroupIO groupIOIntermediate = newGroupIO.openGroup("Geometry"); + REQUIRE(groupIOIntermediate.isValid()); + + HDF5::DatasetIO datasetIO = groupIOIntermediate.openDataset("DataArray"); + REQUIRE(datasetIO.open()); + TestH5ImplicitCopy(std::move(datasetIO), "HDF5::DatasetIO"); + + HDF5::AttributeIO attributeIO = newFileIO.getAttribute("FileVersion"); + TestH5ImplicitCopy(std::move(attributeIO), "HDF5::AttributeReader"); +}