From 2f5dc7d650c32c95735e05e1192ad477ecb4245e Mon Sep 17 00:00:00 2001 From: antonysigma Date: Fri, 28 Jul 2023 08:39:52 -0700 Subject: [PATCH] Constrain the Property object at compile-time (#811) The property struct/class requires a public member function signature `apply(hid_t) const`. Describe the constrain in the C++20 concepts syntax. The primarily goal is to make compiler errors more readable for average users. The variable `HIGHFIVE_HAS_CONCEPTS` can be used to turn off concepts entirely. --- CMake/HighFiveTargetDeps.cmake | 2 ++ CMakeLists.txt | 1 + include/highfive/H5PropertyList.hpp | 36 +++++++++++++++++-- include/highfive/bits/H5PropertyList_misc.hpp | 2 +- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CMake/HighFiveTargetDeps.cmake b/CMake/HighFiveTargetDeps.cmake index 8fddf39e7..da28423bc 100644 --- a/CMake/HighFiveTargetDeps.cmake +++ b/CMake/HighFiveTargetDeps.cmake @@ -36,6 +36,8 @@ if(NOT TARGET libdeps) target_include_directories(libdeps SYSTEM INTERFACE ${HDF5_INCLUDE_DIRS}) target_link_libraries(libdeps INTERFACE ${HDF5_LIBRARIES}) target_compile_definitions(libdeps INTERFACE ${HDF5_DEFINITIONS}) + target_compile_definitions(libdeps INTERFACE HIGHFIVE_HAS_CONCEPTS=$) + # Boost if(HIGHFIVE_USE_BOOST) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fcee8781..f34c5567a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ option(HIGHFIVE_PARALLEL_HDF5 "Enable Parallel HDF5 support" OFF) option(HIGHFIVE_BUILD_DOCS "Enable documentation building" ON) option(HIGHFIVE_VERBOSE "Set logging level to verbose." OFF) option(HIGHFIVE_GLIBCXX_ASSERTIONS "Enable bounds check for STL." OFF) +option(HIGHFIVE_HAS_CONCEPTS "Print readable compiler errors w/ C++20 concepts" ON) # Controls if HighFive classes are friends of each other. # diff --git a/include/highfive/H5PropertyList.hpp b/include/highfive/H5PropertyList.hpp index db541a42f..53b3c4a13 100644 --- a/include/highfive/H5PropertyList.hpp +++ b/include/highfive/H5PropertyList.hpp @@ -133,6 +133,26 @@ class PropertyListBase: public Object { friend T details::get_plist(const U&, hid_t (*f)(hid_t)); }; +/// \interface PropertyInterface +/// \brief HDF5 file property object +/// +/// A property is an object which is expected to have a method with the +/// following signature `void apply(hid_t hid) const` +/// +/// \sa Instructions to document C++20 concepts with Doxygen: https://github.com/doxygen/doxygen/issues/2732#issuecomment-509629967 +/// +/// \cond +#if HIGHFIVE_HAS_CONCEPTS && __cplusplus >= 202002L +template +concept PropertyInterface = requires(P p, const hid_t hid) { + {p.apply(hid)}; +}; + +#else +#define PropertyInterface typename +#endif +/// \endcond + /// /// \brief HDF5 property Lists /// @@ -149,8 +169,8 @@ class PropertyList: public PropertyListBase { /// Add a property to this property list. /// A property is an object which is expected to have a method with the /// following signature void apply(hid_t hid) const - /// - template + /// \tparam PropertyInterface + template void add(const P& property); /// @@ -438,6 +458,7 @@ class PageBufferSize { #endif /// \brief Set hints as to how many links to expect and their average length +/// \implements PropertyInterface /// class EstimatedLinkInfo { public: @@ -463,6 +484,7 @@ class EstimatedLinkInfo { }; +/// \implements PropertyInterface class Chunking { public: explicit Chunking(const std::vector& dims); @@ -481,6 +503,7 @@ class Chunking { std::vector _dims; }; +/// \implements PropertyInterface class Deflate { public: explicit Deflate(unsigned level); @@ -492,6 +515,7 @@ class Deflate { const unsigned _level; }; +/// \implements PropertyInterface class Szip { public: explicit Szip(unsigned options_mask = H5_SZIP_EC_OPTION_MASK, @@ -507,6 +531,7 @@ class Szip { const unsigned _pixels_per_block; }; +/// \implements PropertyInterface class Shuffle { public: Shuffle() = default; @@ -521,6 +546,7 @@ class Shuffle { /// The precise time of when HDF5 requests space to store the dataset /// can be configured. Please, consider the upstream documentation for /// `H5Pset_alloc_time`. +/// \implements PropertyInterface class AllocationTime { public: explicit AllocationTime(H5D_alloc_time_t alloc_time); @@ -537,6 +563,7 @@ class AllocationTime { /// Dataset access property to control chunk cache configuration. /// Do not confuse with the similar file access property for H5Pset_cache +/// \implements PropertyInterface class Caching { public: /// https://support.hdfgroup.org/HDF5/doc/RM/H5P/H5Pset_chunk_cache.html for @@ -559,6 +586,7 @@ class Caching { double _w0; }; +/// \implements PropertyInterface class CreateIntermediateGroup { public: explicit CreateIntermediateGroup(bool create = true); @@ -579,6 +607,7 @@ class CreateIntermediateGroup { }; #ifdef H5_HAVE_PARALLEL +/// \implements PropertyInterface class UseCollectiveIO { public: explicit UseCollectiveIO(bool enable = true); @@ -601,6 +630,7 @@ class UseCollectiveIO { /// creation of this object. This object will not update automatically for later data transfers, /// i.e. `H5Pget_mpio_no_collective_cause` is called in the constructor, and not when fetching /// a value, such as `wasCollective`. +/// \implements PropertyInterface class MpioNoCollectiveCause { public: explicit MpioNoCollectiveCause(const DataTransferProps& dxpl); @@ -636,6 +666,7 @@ struct CreationOrder { /// /// Let user retrieve objects by creation order time instead of name. /// +/// \implements PropertyInterface class LinkCreationOrder { public: /// @@ -671,6 +702,7 @@ class LinkCreationOrder { /// Please refer to the upstream documentation of `H5Pset_attr_phase_change` or /// Section 8 (Attributes) in the User Guide, in particular Subsection 8.5. /// +/// \implements PropertyInterface class AttributePhaseChange { public: /// diff --git a/include/highfive/bits/H5PropertyList_misc.hpp b/include/highfive/bits/H5PropertyList_misc.hpp index cf94af832..cef301e53 100644 --- a/include/highfive/bits/H5PropertyList_misc.hpp +++ b/include/highfive/bits/H5PropertyList_misc.hpp @@ -70,7 +70,7 @@ inline void PropertyList::_initializeIfNeeded() { } template -template +template inline void PropertyList::add(const P& property) { _initializeIfNeeded(); property.apply(_hid);