openPMD-api
Attribute.hpp
1 /* Copyright 2017-2020 Fabian Koller
2  *
3  * This file is part of openPMD-api.
4  *
5  * openPMD-api is free software: you can redistribute it and/or modify
6  * it under the terms of of either the GNU General Public License or
7  * the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * openPMD-api is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License and the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * and the GNU Lesser General Public License along with openPMD-api.
19  * If not, see <http://www.gnu.org/licenses/>.
20  */
21 #pragma once
22 
23 #include "openPMD/auxiliary/Variant.hpp"
24 #include "openPMD/Datatype.hpp"
25 
26 #include <algorithm>
27 #include <array>
28 #include <complex>
29 #include <cstdint>
30 #include <iterator>
31 #include <stdexcept>
32 #include <string>
33 #include <type_traits>
34 #include <utility>
35 #include <vector>
36 
37 
38 namespace openPMD
39 {
40 //TODO This might have to be a Writable
41 //Reasoning - Flushes are expected to be done often.
42 //Attributes should not be written unless dirty.
43 //At the moment the dirty check is done at Attributable level,
44 //resulting in all of an Attributables Attributes being written to disk even if only one changes
50 class Attribute :
51  public auxiliary::Variant< Datatype,
52  char, unsigned char, // signed char,
53  short, int, long, long long,
54  unsigned short, unsigned int, unsigned long, unsigned long long,
55  float, double, long double,
56  std::complex< float >, std::complex< double >, std::complex< long double >,
57  std::string,
58  std::vector< char >,
59  std::vector< short >,
60  std::vector< int >,
61  std::vector< long >,
62  std::vector< long long >,
63  std::vector< unsigned char >,
64  std::vector< unsigned short >,
65  std::vector< unsigned int >,
66  std::vector< unsigned long >,
67  std::vector< unsigned long long >,
68  std::vector< float >,
69  std::vector< double >,
70  std::vector< long double >,
71  std::vector< std::complex< float > >,
72  std::vector< std::complex< double > >,
73  std::vector< std::complex< long double > >,
74  std::vector< std::string >,
75  std::array< double, 7 >,
76  bool >
77 {
78 public:
79  Attribute(resource r) : Variant(std::move(r))
80  { }
81 
91  template< typename U >
92  U get() const;
93 };
94 
95 template< typename T, typename U, bool isConvertible = std::is_convertible<T, U>::value >
96 struct DoConvert;
97 
98 template< typename T, typename U >
99 struct DoConvert<T, U, false>
100 {
101  template< typename PV >
102  U operator()( PV )
103  {
104  throw std::runtime_error("getCast: no cast possible.");
105  }
106 };
107 
108 template< typename T, typename U >
109 struct DoConvert<T, U, true>
110 {
111  template< typename PV >
112  U operator()( PV pv )
113  {
114  return static_cast< U >( *pv );
115  }
116 };
117 
118 template< typename T, typename U >
119 struct DoConvert<std::vector< T >, std::vector< U >, false>
120 {
121  static constexpr bool convertible = std::is_convertible<T, U>::value;
122 
123  template< typename PV, typename UU = U >
124  auto operator()( PV pv )
125  -> typename std::enable_if< convertible, std::vector< UU > >::type
126  {
127  std::vector< U > u;
128  u.reserve( pv->size() );
129  std::copy( pv->begin(), pv->end(), std::back_inserter(u) );
130  return u;
131  }
132 
133  template< typename PV, typename UU = U >
134  auto operator()( PV )
135  -> typename std::enable_if< !convertible, std::vector< UU > >::type
136  {
137  throw std::runtime_error("getCast: no vector cast possible.");
138  }
139 };
140 
147 template< typename U >
148 inline U
149 getCast( Attribute const & a )
150 {
151  auto v = a.getResource();
152 
153  if(auto pvalue_c = variantSrc::get_if< char >( &v ) )
154  return DoConvert<char, U>{}(pvalue_c);
155  else if(auto pvalue_uc = variantSrc::get_if< unsigned char >( &v ) )
156  return DoConvert<unsigned char, U>{}(pvalue_uc);
157  else if(auto pvalue_s = variantSrc::get_if< short >( &v ) )
158  return DoConvert<short, U>{}(pvalue_s);
159  else if(auto pvalue_i = variantSrc::get_if< int >( &v ) )
160  return DoConvert<int, U>{}(pvalue_i);
161  else if(auto pvalue_l = variantSrc::get_if< long >( &v ) )
162  return DoConvert<long, U>{}(pvalue_l);
163  else if(auto pvalue_ll = variantSrc::get_if< long long >( &v ) )
164  return DoConvert<long long, U>{}(pvalue_ll);
165  else if(auto pvalue_us = variantSrc::get_if< unsigned short >( &v ) )
166  return DoConvert<unsigned short, U>{}(pvalue_us);
167  else if(auto pvalue_ui = variantSrc::get_if< unsigned int >( &v ) )
168  return DoConvert<unsigned int, U>{}(pvalue_ui);
169  else if(auto pvalue_ul = variantSrc::get_if< unsigned long >( &v ) )
170  return DoConvert<unsigned long, U>{}(pvalue_ul);
171  else if(auto pvalue_ull = variantSrc::get_if< unsigned long long >( &v ) )
172  return DoConvert<unsigned long long, U>{}(pvalue_ull);
173  else if(auto pvalue_f = variantSrc::get_if< float >( &v ) )
174  return DoConvert<float, U>{}(pvalue_f);
175  else if(auto pvalue_d = variantSrc::get_if< double >( &v ) )
176  return DoConvert<double, U>{}(pvalue_d);
177  else if(auto pvalue_ld = variantSrc::get_if< long double >( &v ) )
178  return DoConvert<long double, U>{}(pvalue_ld);
179  else if(auto pvalue_cf = variantSrc::get_if< std::complex< float > >( &v ) )
180  return DoConvert<std::complex< float >, U>{}(pvalue_cf);
181  else if(auto pvalue_cd = variantSrc::get_if< std::complex< double > >( &v ) )
182  return DoConvert<std::complex< double >, U>{}(pvalue_cd);
183  else if(auto pvalue_cld = variantSrc::get_if< std::complex< long double > >( &v ) )
184  return DoConvert<std::complex< long double >, U>{}(pvalue_cld);
185  else if(auto pvalue_str = variantSrc::get_if< std::string >( &v ) )
186  return DoConvert<std::string, U>{}(pvalue_str);
187  // vector
188  else if(auto pvalue_vc = variantSrc::get_if< std::vector< char > >( &v ) )
189  return DoConvert<std::vector< char >, U>{}(pvalue_vc);
190  else if(auto pvalue_vuc = variantSrc::get_if< std::vector< unsigned char > >( &v ) )
191  return DoConvert<std::vector< unsigned char >, U>{}(pvalue_vuc);
192  else if(auto pvalue_vs = variantSrc::get_if< std::vector< short > >( &v ) )
193  return DoConvert<std::vector< short >, U>{}(pvalue_vs);
194  else if(auto pvalue_vi = variantSrc::get_if< std::vector< int > >( &v ) )
195  return DoConvert<std::vector< int >, U>{}(pvalue_vi);
196  else if(auto pvalue_vl = variantSrc::get_if< std::vector< long > >( &v ) )
197  return DoConvert<std::vector< long >, U>{}(pvalue_vl);
198  else if(auto pvalue_vll = variantSrc::get_if< std::vector< long long > >( &v ) )
199  return DoConvert<std::vector< long long >, U>{}(pvalue_vll);
200  else if(auto pvalue_vus = variantSrc::get_if< std::vector< unsigned short > >( &v ) )
201  return DoConvert<std::vector< unsigned short >, U>{}(pvalue_vus);
202  else if(auto pvalue_vui = variantSrc::get_if< std::vector< unsigned int > >( &v ) )
203  return DoConvert<std::vector< unsigned int >, U>{}(pvalue_vui);
204  else if(auto pvalue_vul = variantSrc::get_if< std::vector< unsigned long > >( &v ) )
205  return DoConvert<std::vector< unsigned long >, U>{}(pvalue_vul);
206  else if(auto pvalue_vull = variantSrc::get_if< std::vector< unsigned long long > >( &v ) )
207  return DoConvert<std::vector< unsigned long long >, U>{}(pvalue_vull);
208  else if(auto pvalue_vf = variantSrc::get_if< std::vector< float > >( &v ) )
209  return DoConvert<std::vector< float >, U>{}(pvalue_vf);
210  else if(auto pvalue_vd = variantSrc::get_if< std::vector< double > >( &v ) )
211  return DoConvert<std::vector< double >, U>{}(pvalue_vd);
212  else if(auto pvalue_vld = variantSrc::get_if< std::vector< long double > >( &v ) )
213  return DoConvert<std::vector< long double >, U>{}(pvalue_vld);
214  else if(auto pvalue_vcf = variantSrc::get_if< std::vector< std::complex< float > > >( &v ) )
215  return DoConvert<std::vector< std::complex< float > >, U>{}(pvalue_vcf);
216  else if(auto pvalue_vcd = variantSrc::get_if< std::vector< std::complex< double > > >( &v ) )
217  return DoConvert<std::vector< std::complex< double > >, U>{}(pvalue_vcd);
218  else if(auto pvalue_vcld = variantSrc::get_if< std::vector< std::complex< long double > > >( &v ) )
219  return DoConvert<std::vector< std::complex< long double > >, U>{}(pvalue_vcld);
220  else if(auto pvalue_vstr = variantSrc::get_if< std::vector< std::string > >( &v ) )
221  return DoConvert<std::vector< std::string >, U>{}(pvalue_vstr);
222  // extra
223  else if(auto pvalue_vad = variantSrc::get_if< std::array< double, 7 > >( &v ) )
224  return DoConvert<std::array< double, 7 >, U>{}(pvalue_vad);
225  else if(auto pvalue_b = variantSrc::get_if< bool >( &v ) )
226  return DoConvert<bool, U>{}(pvalue_b);
227  else
228  throw std::runtime_error("getCast: unknown Datatype.");
229 }
230 
231 template< typename U >
232 U Attribute::get() const
233 {
234  return getCast< U >( Variant::getResource() );
235 }
236 
237 } // namespace openPMD
U get() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:232
Definition: Attribute.hpp:96
STL namespace.
Generic object to store a set of datatypes in without losing type safety.
Definition: Variant.hpp:38
U getCast(Attribute const &a)
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:149
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard...
Definition: Attribute.hpp:50
Public definitions of openPMD-api.
Definition: Date.cpp:29
resource getResource() const
Retrieve the stored generic object.
Definition: Variant.hpp:72