22 #ifndef GenUnitsClassPlugin20150310H
23 #define GenUnitsClassPlugin20150310H
25 #include <boost/config/warning_disable.hpp>
26 #include <boost/spirit/include/qi.hpp>
27 #include <boost/spirit/include/qi_lit.hpp>
28 #include <boost/spirit/include/phoenix_bind.hpp>
29 #include <boost/spirit/include/phoenix_core.hpp>
30 #include <boost/spirit/include/phoenix_operator.hpp>
31 #include <boost/spirit/include/phoenix_stl.hpp>
32 #include <boost/spirit/include/qi_expect.hpp>
33 #include <boost/lambda/lambda.hpp>
35 #include <boost/algorithm/string/replace.hpp>
42 #include <boost/bimap.hpp>
53 namespace qi = boost::spirit::qi;
54 namespace ascii = boost::spirit::ascii;
55 namespace phoenix = boost::phoenix;
58 inline boost::bimap< std::string,char > make_dim_bimap()
60 typedef boost::bimap< std::string, char > dim_bimap;
61 typedef dim_bimap::value_type dimension;
64 dims.insert( dimension(
"length",
'L') );
65 dims.insert( dimension(
"time",
'T') );
66 dims.insert( dimension(
"mass",
'M') );
67 dims.insert( dimension(
"plane_angle",
'A') );
68 dims.insert( dimension(
"solid_angle",
'S') );
69 dims.insert( dimension(
"current",
'I') );
70 dims.insert( dimension(
"temperature",
'K') );
71 dims.insert( dimension(
"amount",
'N') );
72 dims.insert( dimension(
"luminous_intensity",
'J') );
73 dims.insert( dimension(
"information",
'B') );
74 dims.insert( dimension(
"dimensionless",
'-') );
80 inline void push_char_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
const char& c)
82 vc.push_back(std::string(1, c));
84 typedef boost::bimap< std::string, char > bimap_type;
85 bimap_type dim_bimap = make_dim_bimap();
87 bimap_type::right_const_iterator it_right = dim_bimap.right.find(c);
89 vs.push_back(it_right -> second);
93 inline void push_string_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
const std::string& s)
97 typedef boost::bimap< std::string, char > bimap_type;
98 bimap_type dim_bimap = make_dim_bimap();
100 bimap_type::left_const_iterator it_left = dim_bimap.left.find(s);
102 vc.push_back(std::string(1, it_left -> second));
106 inline void push_char(std::vector<std::string>& vc,
const char& c)
108 vc.push_back(std::string(1, c));
112 inline void push_char_vec(std::vector<std::string>& vc,
const std::vector<char>& c)
114 vc.push_back(std::string(c.begin(), c.end()));
118 template <
typename Iterator>
119 bool parse_base_dimensions(Iterator first, Iterator last, std::vector<double>& base_dim_powers, std::vector<std::string>& base_dim_chars, std::vector<std::string>& base_dim_strings)
129 using qi::phrase_parse;
131 using phoenix::push_back;
137 bool r = phrase_parse(
140 +((char_(
"LTMASIKNJB-")[phoenix::bind(&push_char_base, phoenix::ref(base_dim_chars), phoenix::ref(base_dim_strings), _1)] |
141 ((ascii::string(
"length") | ascii::string(
"time") | ascii::string(
"mass") | ascii::string(
"plane_angle") | ascii::string(
"solid_angle") | ascii::string(
"current") | ascii::string(
"temperature") | ascii::string(
"amount") | ascii::string(
"luminous_intensity") | ascii::string(
"information") | ascii::string(
"dimensionless"))[phoenix::bind(&push_string_base, phoenix::ref(base_dim_chars), phoenix::ref(base_dim_strings), _1)])) >>
142 -(ascii::string(
"_base_dimension")) >>
143 ((
'^' > double_[push_back(phoenix::ref(base_dim_powers), _1)]) | eps[push_back(phoenix::ref(base_dim_powers), 1)])),
151 catch(
const std::runtime_error& e)
159 template <
typename Iterator>
160 bool parse_derived_dimensions(Iterator first, Iterator last, std::vector<std::string>& derived_dim_operators, std::vector<std::string>& derived_dim_strings)
165 using qi::phrase_parse;
167 using phoenix::push_back;
172 std::vector<std::string> params;
173 bool r = boost::spirit::qi::parse(first, last,
174 +((+char_(
"a-z1_"))[phoenix::bind(&push_char_vec, boost::phoenix::ref(params), _1)] >>
175 -(*char_(
" ") >> (char_(
"*/")[phoenix::bind(&push_char, phoenix::ref(derived_dim_operators), _1)] | eps[push_back(phoenix::ref(derived_dim_operators), std::string(
"*"))]) >> *char_(
" "))));
177 if(derived_dim_operators.size())
178 derived_dim_operators.pop_back();
180 for(std::vector<std::string>::iterator it = params.begin(), end = params.end(); it!=end; ++it)
182 std::string::size_type dim_pos = it->find(
"_dimension");
183 if(dim_pos != std::string::npos)
184 *it = it->substr(0, dim_pos);
186 derived_dim_strings.push_back(*it);
193 catch(
const std::runtime_error& e)
201 std::string get_field_type_name(google::protobuf::FieldDescriptor::CppType type){
203 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
204 return "google::protobuf::int32";
205 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
206 return "google::protobuf::int64";
207 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
208 return "google::protobuf::uint32";
209 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
210 return "google::protobuf::uint64";
211 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
213 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
238 inline void include_units_headers(
const std::string& sysname, std::ostream& os){
247 if(sysname ==
"si" ||
248 sysname ==
"boost::units::si" ||
249 sysname ==
"angle::radian")
251 os <<
"#include <boost/units/systems/si.hpp>" <<std::endl;
253 else if(sysname ==
"cgs" ||
254 sysname ==
"boost::units::cgs")
256 os <<
"#include <boost/units/systems/cgs.hpp>" <<std::endl;
258 else if(sysname ==
"celsius" ||
259 sysname ==
"boost::units::celsius" ||
260 sysname ==
"temperature::celsius")
262 os <<
"#include <boost/units/systems/temperature/celsius.hpp>" <<std::endl;
264 else if(sysname ==
"fahrenheit" ||
265 sysname ==
"boost::units::fahrenheit" ||
266 sysname ==
"temperature::fahrenheit")
268 os <<
"#include <boost/units/systems/temperature/fahrenheit.hpp>" <<std::endl;
270 else if(sysname ==
"degree" ||
271 sysname ==
"boost::units::degree" ||
272 sysname ==
"angle::degree")
274 os <<
"#include <boost/units/systems/angle/degrees.hpp>" <<std::endl;
276 else if(sysname ==
"gradian" ||
277 sysname ==
"boost::units::gradian" ||
278 sysname ==
"angle::gradian")
280 os <<
"#include <boost/units/systems/angle/gradians.hpp>" <<std::endl;
282 else if(sysname ==
"revolution" ||
283 sysname ==
"boost::units::revolution" ||
284 sysname ==
"angle::revolution")
286 os <<
"#include <boost/units/systems/angle/revolutions.hpp>" <<std::endl;
291 std::string sysname_sub = boost::replace_all_copy(sysname,
"::",
"/");
292 os <<
"#include \"" <<sysname_sub <<
".hpp\"" <<std::endl;
299 inline void include_base_unit_headers(
const std::string& base_unit_category_and_name, std::ostream& os){
301 std::string cat_name_sub = boost::replace_all_copy(base_unit_category_and_name,
"::",
"/");
302 os <<
"#include <boost/units/base_units/" <<cat_name_sub <<
".hpp>" <<std::endl;
305 inline void add_absolute(std::string& before, std::string& after)
307 before =
"boost::units::absolute<" + before;
311 inline void add_prefix(
const std::string& prefix, std::string& before, std::string& after)
314 if(prefix ==
"yotta") power = 24;
315 else if(prefix ==
"zetta") power = 21;
316 else if(prefix ==
"exa") power = 18;
317 else if(prefix ==
"peta") power = 15;
318 else if(prefix ==
"tera") power = 12;
319 else if(prefix ==
"giga") power = 9;
320 else if(prefix ==
"mega") power = 6;
321 else if(prefix ==
"kilo") power = 3;
322 else if(prefix ==
"hecto") power = 2;
323 else if(prefix ==
"deka") power = 1;
324 else if(prefix ==
"deci") power = -1;
325 else if(prefix ==
"centi") power = -2;
326 else if(prefix ==
"milli") power = -3;
327 else if(prefix ==
"micro") power = -6;
328 else if(prefix ==
"nano") power = -9;
329 else if(prefix ==
"pico") power = -12;
330 else if(prefix ==
"femto") power = -15;
331 else if(prefix ==
"atto") power = -18;
332 else if(prefix ==
"zepto") power = -21;
333 else if(prefix ==
"yocto") power = -24;
335 throw(std::runtime_error(std::string(
"Invalid SI prefix: " + prefix)));
337 std::stringstream power_ss;
340 before =
"boost::units::make_scaled_unit<" + before;
341 after +=
", boost::units::scale<10, boost::units::static_rational<" + power_ss.str() +
"> > >::type ";
346 inline void construct_units_typedef_from_dimension(
const std::string& fieldname,
const std::string& sysname,
const bool& absolute,
const std::string& prefix, std::ostream& os){
349 std::string sysname_ns;
350 if(sysname ==
"si" || sysname ==
"cgs" || sysname ==
"celsius" || sysname ==
"fahrenheit" || sysname ==
"degree" || sysname ==
"gradian" || sysname ==
"revolution")
351 sysname_ns =
"boost::units::"+sysname+
"::system";
352 else if(sysname ==
"boost::units::si" || sysname ==
"boost::units::cgs")
353 sysname_ns = sysname+
"::system";
354 else if(sysname ==
"temperature::celsius" || sysname ==
"temperature::fahrenheit")
355 sysname_ns = boost::replace_all_copy(sysname,
"temperature::",
"boost::units::");
356 else if(sysname ==
"angle::degree" || sysname ==
"angle::gradian" || sysname ==
"angle::revolution")
357 sysname_ns = boost::replace_all_copy(sysname,
"angle::",
"boost::units::") +
"::system";
358 else if(sysname ==
"angle::radian")
359 sysname_ns =
"boost::units::si::system";
361 sysname_ns = sysname;
366 if(absolute && !prefix.empty())
367 throw(std::runtime_error(std::string(
"'prefix' is not supported with an absolute temperature field")));
370 add_absolute(before, after);
373 add_prefix(prefix, before, after);
377 os <<
"typedef " << before <<
"boost::units::unit<" <<fieldname <<
"_dimension," <<sysname_ns <<
"> " << after <<fieldname <<
"_unit;" <<std::endl;
382 inline void construct_base_dims_typedef(
const std::vector<std::string>& dim_vec,
const std::vector<double>& power_vec,
const std::string& fieldname,
const std::string& sysname,
const bool& rel_temperature,
const std::string& prefix, std::ostream& os){
384 bool temperature_dimension =
false;
385 if(dim_vec[0] ==
"temperature" && dim_vec.size() == 1)
386 temperature_dimension =
true;
387 if(dim_vec[0] ==
"dimensionless" && dim_vec.size() == 1)
389 os <<
"typedef boost::units::dimensionless_type " <<fieldname <<
"_dimension;" <<std::endl;;
393 os <<
"typedef boost::units::derived_dimension< ";
394 for(
int i=0; i<dim_vec.size(); i++){
395 os <<
"boost::units::" <<dim_vec[i] <<
"_base_dimension," <<power_vec[i] ;
396 if(i != dim_vec.size()-1)
399 os <<
" >::type " <<fieldname <<
"_dimension;" <<std::endl;
403 construct_units_typedef_from_dimension(fieldname, sysname,
404 temperature_dimension && !rel_temperature,
410 inline void construct_derived_dims_typedef(
const std::vector<std::string>& dim_vec,
const std::vector<std::string>& operator_vec,
const std::string& fieldname,
const std::string& sysname,
const bool& rel_temperature,
const std::string& prefix, std::ostream& os){
413 bool temperature_dimension =
false;
415 if (dim_vec.size() == 1){
416 if(dim_vec[0] ==
"temperature")
417 temperature_dimension =
true;
418 if(dim_vec[0] ==
"dimensionless")
419 os <<
"typedef boost::units::dimensionless_type " <<fieldname <<
"_dimension;" <<std::endl;
421 os <<
"typedef boost::units::" <<dim_vec[0] <<
"_dimension " <<fieldname <<
"_dimension;" <<std::endl;
427 std::string result = dim_vec[0];
428 for(
int i=0; i<operator_vec.size(); i++){
429 if(operator_vec[i] ==
"/")
430 result =
"boost::mpl::divides<boost::units::" + result +
"_dimension,boost::units::" + dim_vec[i+1] +
"_dimension>::type";
431 else if(operator_vec[i] ==
"*")
432 result =
"boost::mpl::times<boost::units::" + result +
"_dimension,boost::units::" + dim_vec[i+1] +
"_dimension>::type";
434 os <<result <<
" " <<fieldname <<
"_dimension;" <<std::endl;
438 construct_units_typedef_from_dimension(fieldname, sysname,
439 temperature_dimension && !rel_temperature,
451 inline void construct_units_typedef_from_base_unit(
const std::string& fieldname,
const std::string& base_unit_category_and_name,
const bool& rel_temperature,
const std::string& prefix, std::ostream& os){
453 bool temperature_unit =
false;
456 if((base_unit_category_and_name.find(
"temperature") != std::string::npos) || (base_unit_category_and_name.find(
"kelvin") != std::string::npos))
457 temperature_unit =
true;
459 bool absolute = temperature_unit && !rel_temperature;
464 add_absolute(before, after);
467 add_prefix(prefix, before, after);
471 os <<
"typedef " << before <<
"boost::units::" <<base_unit_category_and_name <<
"_base_unit::unit_type " << after <<fieldname <<
"_unit;" <<std::endl;
478 inline void construct_field_class_plugin(
const std::string& fieldname, std::ostream& os,
const std::string& value_type,
bool is_repeated){
482 os <<
"template<typename Quantity >" <<std::endl;
483 os <<
" void set_" <<fieldname <<
"_with_units(";
486 os <<
"Quantity value_w_units)" <<std::endl;
487 os <<
" { set_" <<fieldname <<
"(";
490 os <<
"boost::units::quantity<" <<fieldname <<
"_unit," <<value_type <<
" >(value_w_units).value() ); };" <<std::endl;
495 os <<
"template<typename Quantity >" <<std::endl;
496 os <<
" void add_" <<fieldname <<
"_with_units(Quantity value_w_units)" <<std::endl;
497 os <<
" { add_" <<fieldname <<
"(boost::units::quantity<" <<fieldname <<
"_unit," <<value_type <<
" >(value_w_units).value() ); };" <<std::endl;
503 os <<
"template<typename Quantity >" <<std::endl;
504 os <<
" Quantity " <<fieldname <<
"_with_units(";
507 os <<
") const" <<std::endl;
508 os <<
" { return Quantity(" <<fieldname <<
"(";
511 os <<
") * " <<fieldname <<
"_unit()); };" <<std::endl;
515 os <<
"boost::units::quantity< " <<fieldname <<
"_unit," <<value_type <<
" > " <<fieldname <<
"_with_units(";
518 os <<
") const" <<std::endl;
519 os <<
" { return " <<fieldname <<
"_with_units<boost::units::quantity< " <<fieldname <<
"_unit," <<value_type <<
" > >(";
522 os <<
"); };" <<std::endl;