Skip to content

Commit

Permalink
Constrain the Property object at compile-time (#811)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
antonysigma authored Jul 28, 2023
1 parent 3f005dc commit 2f5dc7d
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CMake/HighFiveTargetDeps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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=$<BOOL:${HIGHFIVE_HAS_CONCEPTS}>)


# Boost
if(HIGHFIVE_USE_BOOST)
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
#
Expand Down
36 changes: 34 additions & 2 deletions include/highfive/H5PropertyList.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename P>
concept PropertyInterface = requires(P p, const hid_t hid) {
{p.apply(hid)};
};

#else
#define PropertyInterface typename
#endif
/// \endcond

///
/// \brief HDF5 property Lists
///
Expand All @@ -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 <typename P>
/// \tparam PropertyInterface
template <PropertyInterface P>
void add(const P& property);

///
Expand Down Expand Up @@ -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:
Expand All @@ -463,6 +484,7 @@ class EstimatedLinkInfo {
};


/// \implements PropertyInterface
class Chunking {
public:
explicit Chunking(const std::vector<hsize_t>& dims);
Expand All @@ -481,6 +503,7 @@ class Chunking {
std::vector<hsize_t> _dims;
};

/// \implements PropertyInterface
class Deflate {
public:
explicit Deflate(unsigned level);
Expand All @@ -492,6 +515,7 @@ class Deflate {
const unsigned _level;
};

/// \implements PropertyInterface
class Szip {
public:
explicit Szip(unsigned options_mask = H5_SZIP_EC_OPTION_MASK,
Expand All @@ -507,6 +531,7 @@ class Szip {
const unsigned _pixels_per_block;
};

/// \implements PropertyInterface
class Shuffle {
public:
Shuffle() = default;
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -559,6 +586,7 @@ class Caching {
double _w0;
};

/// \implements PropertyInterface
class CreateIntermediateGroup {
public:
explicit CreateIntermediateGroup(bool create = true);
Expand All @@ -579,6 +607,7 @@ class CreateIntermediateGroup {
};

#ifdef H5_HAVE_PARALLEL
/// \implements PropertyInterface
class UseCollectiveIO {
public:
explicit UseCollectiveIO(bool enable = true);
Expand All @@ -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);
Expand Down Expand Up @@ -636,6 +666,7 @@ struct CreationOrder {
///
/// Let user retrieve objects by creation order time instead of name.
///
/// \implements PropertyInterface
class LinkCreationOrder {
public:
///
Expand Down Expand Up @@ -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:
///
Expand Down
2 changes: 1 addition & 1 deletion include/highfive/bits/H5PropertyList_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ inline void PropertyList<T>::_initializeIfNeeded() {
}

template <PropertyType T>
template <typename P>
template <PropertyInterface P>
inline void PropertyList<T>::add(const P& property) {
_initializeIfNeeded();
property.apply(_hid);
Expand Down

0 comments on commit 2f5dc7d

Please sign in to comment.