Skip to content

Commit e00bede

Browse files
ax3lfranzpoeschel
andauthored
Release: 0.14.2 (#1090)
* Bug fix: Don't forget closing files (#1083) * Failing test * Bug fix: Don't forget closing files * HDF5: Fix String Vlen Attribute Reads (#1084) We inofficially try to also support HDF5 variable lengths strings in reading, just to increase compatibility. This was never working it seems. * Fix reading of vector attributes with only one contained value (#1085) * Failing test * Conversions in Attribute.hpp 1) single values to 1-value vectors 2) vectors to arrays 3) arrays to vectors * Some cleanup in Attribute.hpp 1) Simplify types in DoConvert, remove unnecessary template parameter 2) Replace a long if-then-else chain by variantSrc::visit * CoreTest: Fix std::array constructors Make more widely compile-able. * Explicit casting in some places This avoids some warnings * Intel compilers: Don't use variantSrc::visit They don't like it * Remove scattered checks for vector attributes * Generalize icpc guard As defined in CMake for compiler identification. * Doc ICC version (2021.3.0) * setAttribute: Reject Empty Strings (#1087) * setAttribute: Reject Empty Strings Some backends, especially HDF5, do not allow us to define zero-sized strings. We thus need to catch this in the frontend and forward the restriction to the user. * Test: setAttribute("key", "") throws * setAttribute Check: C++14 compatible * Don't read iterations if they have already been parsed (#1089) * Release: 0.14.2 Co-authored-by: Franz Pöschel <[email protected]>
1 parent 7f499d4 commit e00bede

File tree

18 files changed

+342
-114
lines changed

18 files changed

+342
-114
lines changed

CHANGELOG.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@
33
Changelog
44
=========
55

6+
0.14.2
7+
------
8+
**Date:** 2021-08-17
9+
10+
Various Reader Fixes
11+
12+
This releases fixes regressions in reads, closing files properly, avoiding inefficient parsing and allowing more permissive casts in attribute reads.
13+
(Inofficial) support for HDF5 vlen string reads has been fixed.
14+
15+
Changes to "0.14.1"
16+
^^^^^^^^^^^^^^^^^^^
17+
18+
Bug Fixes
19+
"""""""""
20+
21+
- do not forget to close files #1083
22+
- reading of vector attributes with only one contained value #1085
23+
- do not read iterations if they have already been parsed #1089
24+
- HDF5: fix string vlen attribute reads #1084
25+
26+
Other
27+
"""""
28+
29+
- ``setAttribute``: reject empty strings #1087
30+
31+
632
0.14.1
733
------
834
**Date:** 2021-08-04

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ contact:
2525
orcid: https://orcid.org/0000-0003-1943-7141
2626
2727
title: "openPMD-api: C++ & Python API for Scientific I/O with openPMD"
28-
version: 0.14.1
28+
version: 0.14.2
2929
repository-code: https://github.com/openPMD/openPMD-api
3030
doi: 10.14278/rodare.27
3131
license: LGPL-3.0-or-later

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
cmake_minimum_required(VERSION 3.15.0)
44

5-
project(openPMD VERSION 0.14.1) # LANGUAGES CXX
5+
project(openPMD VERSION 0.14.2) # LANGUAGES CXX
66

77
# the openPMD "markup"/"schema" standard version
88
set(openPMD_STANDARD_VERSION 1.1.0)

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@
8383
# built documents.
8484
#
8585
# The short X.Y version.
86-
version = u'0.14.1'
86+
version = u'0.14.2'
8787
# The full version, including alpha/beta/rc tags.
88-
release = u'0.14.1'
88+
release = u'0.14.2'
8989

9090
# The language for content autogenerated by Sphinx. Refer to documentation
9191
# for a list of supported languages.

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ openPMD-api version supported openPMD standard versions
4242
======================== ===================================
4343
``2.0.0+`` ``2.0.0+`` (not released yet)
4444
``1.0.0+`` ``1.0.1-1.1.0`` (not released yet)
45-
``0.13.1-0.14.1`` (beta) ``1.0.0-1.1.0``
45+
``0.13.1-0.14.2`` (beta) ``1.0.0-1.1.0``
4646
``0.1.0-0.12.0`` (alpha) ``1.0.0-1.1.0``
4747
======================== ===================================
4848

include/openPMD/backend/Attributable.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <vector>
3232
#include <string>
3333
#include <cstddef>
34+
#include <type_traits>
3435

3536
// expose private and protected members for invasive testing
3637
#ifndef OPENPMD_protected
@@ -83,8 +84,29 @@ class AttributableData
8384
private:
8485
A_MAP m_attributes;
8586
};
87+
88+
/** Verify values of attributes in the frontend
89+
*
90+
* verify string attributes are not empty (backend restriction, e.g., HDF5)
91+
*/
92+
template< typename T >
93+
inline void
94+
attr_value_check( std::string const /* key */, T /* value */ )
95+
{
8696
}
8797

98+
template< >
99+
inline void
100+
attr_value_check( std::string const key, std::string const value )
101+
{
102+
if( value.empty() )
103+
throw std::runtime_error(
104+
"[setAttribute] Value for string attribute '" + key +
105+
"' must not be empty!" );
106+
}
107+
108+
} // namespace internal
109+
88110
/** @brief Layer to manage storage of attributes associated with file objects.
89111
*
90112
* Mandatory and user-defined Attributes and their data for every object in the
@@ -394,6 +416,8 @@ template< typename T >
394416
inline bool
395417
AttributableInterface::setAttribute( std::string const & key, T value )
396418
{
419+
internal::attr_value_check( key, value );
420+
397421
auto & attri = get();
398422
if(IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess )
399423
{
@@ -420,6 +444,7 @@ AttributableInterface::setAttribute( std::string const & key, T value )
420444
return false;
421445
}
422446
}
447+
423448
inline bool
424449
AttributableInterface::setAttribute( std::string const & key, char const value[] )
425450
{

include/openPMD/backend/Attribute.hpp

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ struct DoConvert;
9898
template< typename T, typename U >
9999
struct DoConvert<T, U, false>
100100
{
101-
template< typename PV >
102-
U operator()( PV )
101+
U operator()( T * )
103102
{
104103
throw std::runtime_error("getCast: no cast possible.");
105104
}
@@ -108,8 +107,7 @@ struct DoConvert<T, U, false>
108107
template< typename T, typename U >
109108
struct DoConvert<T, U, true>
110109
{
111-
template< typename PV >
112-
U operator()( PV pv )
110+
U operator()( T * pv )
113111
{
114112
return static_cast< U >( *pv );
115113
}
@@ -120,8 +118,8 @@ struct DoConvert<std::vector< T >, std::vector< U >, false>
120118
{
121119
static constexpr bool convertible = std::is_convertible<T, U>::value;
122120

123-
template< typename PV, typename UU = U >
124-
auto operator()( PV pv )
121+
template< typename UU = U >
122+
auto operator()( std::vector< T > const * pv )
125123
-> typename std::enable_if< convertible, std::vector< UU > >::type
126124
{
127125
std::vector< U > u;
@@ -130,14 +128,101 @@ struct DoConvert<std::vector< T >, std::vector< U >, false>
130128
return u;
131129
}
132130

133-
template< typename PV, typename UU = U >
134-
auto operator()( PV )
131+
template< typename UU = U >
132+
auto operator()( std::vector< T > const * )
135133
-> typename std::enable_if< !convertible, std::vector< UU > >::type
136134
{
137135
throw std::runtime_error("getCast: no vector cast possible.");
138136
}
139137
};
140138

139+
// conversion cast: turn a single value into a 1-element vector
140+
template< typename T, typename U >
141+
struct DoConvert<T, std::vector< U >, false>
142+
{
143+
static constexpr bool convertible = std::is_convertible<T, U>::value;
144+
145+
template< typename UU = U >
146+
auto operator()( T const * pv )
147+
-> typename std::enable_if< convertible, std::vector< UU > >::type
148+
{
149+
std::vector< U > u;
150+
u.reserve( 1 );
151+
u.push_back( static_cast< U >( *pv ) );
152+
return u;
153+
}
154+
155+
template< typename UU = U >
156+
auto operator()( T const * )
157+
-> typename std::enable_if< !convertible, std::vector< UU > >::type
158+
{
159+
throw std::runtime_error(
160+
"getCast: no scalar to vector conversion possible.");
161+
}
162+
};
163+
164+
// conversion cast: array to vector
165+
// if a backend reports a std::array<> for something where the frontend expects
166+
// a vector
167+
template< typename T, typename U, size_t n >
168+
struct DoConvert<std::array< T, n >, std::vector< U >, false>
169+
{
170+
static constexpr bool convertible = std::is_convertible<T, U>::value;
171+
172+
template< typename UU = U >
173+
auto operator()( std::array< T, n > const * pv )
174+
-> typename std::enable_if< convertible, std::vector< UU > >::type
175+
{
176+
std::vector< U > u;
177+
u.reserve( n );
178+
std::copy( pv->begin(), pv->end(), std::back_inserter(u) );
179+
return u;
180+
}
181+
182+
template< typename UU = U >
183+
auto operator()( std::array< T, n > const * )
184+
-> typename std::enable_if< !convertible, std::vector< UU > >::type
185+
{
186+
throw std::runtime_error(
187+
"getCast: no array to vector conversion possible.");
188+
}
189+
};
190+
191+
// conversion cast: vector to array
192+
// if a backend reports a std::vector<> for something where the frontend expects
193+
// an array
194+
template< typename T, typename U, size_t n >
195+
struct DoConvert<std::vector< T >, std::array< U, n >, false>
196+
{
197+
static constexpr bool convertible = std::is_convertible<T, U>::value;
198+
199+
template< typename UU = U >
200+
auto operator()( std::vector< T > const * pv )
201+
-> typename std::enable_if< convertible, std::array< UU, n > >::type
202+
{
203+
std::array< U, n > u;
204+
if( n != pv->size() )
205+
{
206+
throw std::runtime_error(
207+
"getCast: no vector to array conversion possible "
208+
"(wrong requested array size).");
209+
}
210+
for( size_t i = 0; i < n; ++i )
211+
{
212+
u[ i ] = static_cast< U >( ( *pv )[ i ] );
213+
}
214+
return u;
215+
}
216+
217+
template< typename UU = U >
218+
auto operator()( std::vector< T > const * )
219+
-> typename std::enable_if< !convertible, std::array< UU, n > >::type
220+
{
221+
throw std::runtime_error(
222+
"getCast: no vector to array conversion possible.");
223+
}
224+
};
225+
141226
/** Retrieve a stored specific Attribute and cast if convertible.
142227
*
143228
* @throw std::runtime_error if stored object is not static castable to U.
@@ -150,6 +235,12 @@ getCast( Attribute const & a )
150235
{
151236
auto v = a.getResource();
152237

238+
// icpc 2021.3.0 does not like variantSrc::visit (with mpark-variant)
239+
// we use variantSrc::visit for the other compilers to avoid having an
240+
// endless list of if-then-else
241+
// also, once we switch to C++17, we might throw this out in
242+
// favor of a hopefully working std::visit
243+
#if defined(__ICC) || defined(__INTEL_COMPILER)
153244
if(auto pvalue_c = variantSrc::get_if< char >( &v ) )
154245
return DoConvert<char, U>{}(pvalue_c);
155246
else if(auto pvalue_uc = variantSrc::get_if< unsigned char >( &v ) )
@@ -226,6 +317,15 @@ getCast( Attribute const & a )
226317
return DoConvert<bool, U>{}(pvalue_b);
227318
else
228319
throw std::runtime_error("getCast: unknown Datatype.");
320+
321+
#else
322+
return variantSrc::visit(
323+
[]( auto && containedValue ) -> U {
324+
using containedType = std::decay_t< decltype( containedValue ) >;
325+
return DoConvert< containedType, U >{}( &containedValue );
326+
},
327+
v );
328+
#endif
229329
}
230330

231331
template< typename U >

include/openPMD/version.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
*/
3030
#define OPENPMDAPI_VERSION_MAJOR 0
3131
#define OPENPMDAPI_VERSION_MINOR 14
32-
#define OPENPMDAPI_VERSION_PATCH 1
32+
#define OPENPMDAPI_VERSION_PATCH 2
3333
#define OPENPMDAPI_VERSION_LABEL ""
3434
/** @} */
3535

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def build_extension(self, ext):
156156
setup(
157157
name='openPMD-api',
158158
# note PEP-440 syntax: x.y.zaN but x.y.z.devN
159-
version='0.14.1',
159+
version='0.14.2',
160160
author='Axel Huebl, Franz Poeschel, Fabian Koller, Junmin Gu',
161161
162162
maintainer='Axel Huebl',

src/IO/HDF5/HDF5IOHandler.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,18 +1479,19 @@ HDF5IOHandlerImpl::readAttribute(Writable* writable,
14791479
{
14801480
if( H5Tis_variable_str(attr_type) )
14811481
{
1482-
char* c = nullptr;
1482+
// refs.:
1483+
// https://github.com/HDFGroup/hdf5/blob/hdf5-1_12_0/tools/src/h5dump/h5dump_xml.c
1484+
hsize_t size = H5Tget_size(attr_type); // not yet the actual string length
1485+
std::vector< char > vc(size); // byte buffer to vlen strings
14831486
status = H5Aread(attr_id,
14841487
attr_type,
1485-
c);
1486-
VERIFY(status == 0,
1487-
"[HDF5] Internal error: Failed to read attribute " + attr_name +
1488-
" at " + concrete_h5_file_position(writable));
1489-
a = Attribute(auxiliary::strip(std::string(c), {'\0'}));
1490-
status = H5Dvlen_reclaim(attr_type,
1491-
attr_space,
1492-
H5P_DEFAULT,
1493-
c);
1488+
vc.data());
1489+
auto c_str = *((char**)vc.data()); // get actual string out
1490+
a = Attribute(std::string(c_str));
1491+
// free dynamically allocated vlen memory from H5Aread
1492+
H5Dvlen_reclaim(attr_type, attr_space, H5P_DEFAULT, vc.data());
1493+
// 1.12+:
1494+
//H5Treclaim(attr_type, attr_space, H5P_DEFAULT, vc.data());
14941495
} else
14951496
{
14961497
hsize_t size = H5Tget_size(attr_type);

0 commit comments

Comments
 (0)