24 #ifndef GenUnitsClassPlugin20150310H
25 #define GenUnitsClassPlugin20150310H
27 #include <google/protobuf/descriptor.h>
29 #include <boost/config/warning_disable.hpp>
30 #include <boost/lambda/lambda.hpp>
32 #include <boost/phoenix/bind.hpp>
33 #include <boost/phoenix/core.hpp>
34 #include <boost/phoenix/operator.hpp>
35 #include <boost/phoenix/stl.hpp>
37 #include <boost/spirit/include/qi.hpp>
38 #include <boost/spirit/include/qi_expect.hpp>
39 #include <boost/spirit/include/qi_lit.hpp>
41 #include <boost/algorithm/string/replace.hpp>
48 #include <boost/bimap.hpp>
59 namespace qi = boost::spirit::qi;
60 namespace ascii = boost::spirit::ascii;
61 namespace phoenix = boost::phoenix;
64 inline boost::bimap<std::string, char> make_dim_bimap()
66 typedef boost::bimap<std::string, char> dim_bimap;
67 using dimension = dim_bimap::value_type;
70 dims.insert(dimension(
"length",
'L'));
71 dims.insert(dimension(
"time",
'T'));
72 dims.insert(dimension(
"mass",
'M'));
73 dims.insert(dimension(
"plane_angle",
'A'));
74 dims.insert(dimension(
"solid_angle",
'S'));
75 dims.insert(dimension(
"current",
'I'));
76 dims.insert(dimension(
"temperature",
'K'));
77 dims.insert(dimension(
"amount",
'N'));
78 dims.insert(dimension(
"luminous_intensity",
'J'));
79 dims.insert(dimension(
"information",
'B'));
80 dims.insert(dimension(
"dimensionless",
'-'));
86 inline void push_char_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
89 vc.emplace_back(1, c);
91 using bimap_type = boost::bimap<std::string, char>;
92 bimap_type dim_bimap = make_dim_bimap();
94 bimap_type::right_const_iterator it_right = dim_bimap.right.find(c);
96 vs.push_back(it_right->second);
100 inline void push_string_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
101 const std::string& s)
105 using bimap_type = boost::bimap<std::string, char>;
106 bimap_type dim_bimap = make_dim_bimap();
108 bimap_type::left_const_iterator it_left = dim_bimap.left.find(s);
110 vc.emplace_back(1, it_left->second);
114 inline void push_char(std::vector<std::string>& vc,
const char& c) { vc.emplace_back(1, c); }
117 inline void push_char_vec(std::vector<std::string>& vc,
const std::vector<char>& c)
119 vc.emplace_back(c.begin(), c.end());
123 template <
typename Iterator>
124 bool parse_base_dimensions(Iterator first, Iterator last, std::vector<double>& base_dim_powers,
125 std::vector<std::string>& base_dim_chars,
126 std::vector<std::string>& base_dim_strings)
133 using phoenix::push_back;
138 using qi::phrase_parse;
142 bool r = phrase_parse(
145 +((char_(
"LTMASIKNJB-")[phoenix::bind(&push_char_base, phoenix::ref(base_dim_chars),
146 phoenix::ref(base_dim_strings), _1)] |
147 ((ascii::string(
"length") | ascii::string(
"time") | ascii::string(
"mass") |
148 ascii::string(
"plane_angle") | ascii::string(
"solid_angle") |
149 ascii::string(
"current") | ascii::string(
"temperature") | ascii::string(
"amount") |
150 ascii::string(
"luminous_intensity") | ascii::string(
"information") |
151 ascii::string(
"dimensionless"))[phoenix::bind(
152 &push_string_base, phoenix::ref(base_dim_chars), phoenix::ref(base_dim_strings),
154 -(ascii::string(
"_base_dimension")) >>
155 ((
'^' > double_[push_back(phoenix::ref(base_dim_powers), _1)]) |
156 eps[push_back(phoenix::ref(base_dim_powers), 1)])),
164 catch (
const std::runtime_error& e)
171 template <
typename Iterator>
172 bool parse_derived_dimensions(Iterator first, Iterator last,
173 std::vector<std::string>& derived_dim_operators,
174 std::vector<std::string>& derived_dim_strings)
177 using phoenix::push_back;
182 using qi::phrase_parse;
186 std::vector<std::string> params;
187 bool r = boost::spirit::qi::parse(
189 +((+char_(
"a-z1_"))[phoenix::bind(&push_char_vec, boost::phoenix::ref(params), _1)] >>
191 (char_(
"*/")[phoenix::bind(&push_char, phoenix::ref(derived_dim_operators), _1)] |
192 eps[push_back(phoenix::ref(derived_dim_operators), std::string(
"*"))]) >>
195 if (derived_dim_operators.size())
196 derived_dim_operators.pop_back();
198 for (
auto& param : params)
200 std::string::size_type dim_pos = param.find(
"_dimension");
201 if (dim_pos != std::string::npos)
202 param = param.substr(0, dim_pos);
204 derived_dim_strings.push_back(param);
211 catch (
const std::runtime_error& e)
218 inline std::string get_field_type_name(google::protobuf::FieldDescriptor::CppType type)
222 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
return "google::protobuf::int32";
223 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
return "google::protobuf::int64";
224 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
return "google::protobuf::uint32";
225 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
return "google::protobuf::uint64";
226 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
return "double";
227 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
return "float";
228 default:
return "double";
249 inline void include_units_headers(
const std::string& sysname, std::ostream& os)
259 if (sysname ==
"si" || sysname ==
"boost::units::si" || sysname ==
"angle::radian")
261 os <<
"#include <boost/units/systems/si.hpp>" << std::endl;
263 else if (sysname ==
"cgs" || sysname ==
"boost::units::cgs")
265 os <<
"#include <boost/units/systems/cgs.hpp>" << std::endl;
267 else if (sysname ==
"celsius" || sysname ==
"boost::units::celsius" ||
268 sysname ==
"temperature::celsius")
270 os <<
"#include <boost/units/systems/temperature/celsius.hpp>" << std::endl;
272 else if (sysname ==
"fahrenheit" || sysname ==
"boost::units::fahrenheit" ||
273 sysname ==
"temperature::fahrenheit")
275 os <<
"#include <boost/units/systems/temperature/fahrenheit.hpp>" << std::endl;
277 else if (sysname ==
"degree" || sysname ==
"boost::units::degree" || sysname ==
"angle::degree")
279 os <<
"#include <boost/units/systems/angle/degrees.hpp>" << std::endl;
281 else if (sysname ==
"gradian" || sysname ==
"boost::units::gradian" ||
282 sysname ==
"angle::gradian")
284 os <<
"#include <boost/units/systems/angle/gradians.hpp>" << std::endl;
286 else if (sysname ==
"revolution" || sysname ==
"boost::units::revolution" ||
287 sysname ==
"angle::revolution")
289 os <<
"#include <boost/units/systems/angle/revolutions.hpp>" << std::endl;
294 std::string sysname_sub = boost::replace_all_copy(sysname,
"::",
"/");
295 os <<
"#include \"" << sysname_sub <<
".hpp\"" << std::endl;
302 inline void include_base_unit_headers(
const std::string& base_unit_category_and_name,
306 std::string cat_name_sub = boost::replace_all_copy(base_unit_category_and_name,
"::",
"/");
307 os <<
"#include <boost/units/base_units/" << cat_name_sub <<
".hpp>" << std::endl;
310 inline void add_absolute(std::string& before, std::string& after)
312 before =
"boost::units::absolute<" + before;
316 inline void add_prefix(
const std::string& prefix, std::string& before, std::string& after)
319 if (prefix ==
"yotta")
321 else if (prefix ==
"zetta")
323 else if (prefix ==
"exa")
325 else if (prefix ==
"peta")
327 else if (prefix ==
"tera")
329 else if (prefix ==
"giga")
331 else if (prefix ==
"mega")
333 else if (prefix ==
"kilo")
335 else if (prefix ==
"hecto")
337 else if (prefix ==
"deka")
339 else if (prefix ==
"deci")
341 else if (prefix ==
"centi")
343 else if (prefix ==
"milli")
345 else if (prefix ==
"micro")
347 else if (prefix ==
"nano")
349 else if (prefix ==
"pico")
351 else if (prefix ==
"femto")
353 else if (prefix ==
"atto")
355 else if (prefix ==
"zepto")
357 else if (prefix ==
"yocto")
360 throw(std::runtime_error(std::string(
"Invalid SI prefix: " + prefix)));
362 std::stringstream power_ss;
365 before =
"boost::units::make_scaled_unit<" + before;
366 after +=
", boost::units::scale<10, boost::units::static_rational<" + power_ss.str() +
371 inline void construct_units_typedef_from_dimension(
const std::string& fieldname,
372 const std::string& sysname,
const bool& absolute,
373 const std::string& prefix, std::ostream& os)
376 std::string sysname_ns;
377 if (sysname ==
"si" || sysname ==
"cgs" || sysname ==
"celsius" || sysname ==
"fahrenheit" ||
378 sysname ==
"degree" || sysname ==
"gradian" || sysname ==
"revolution")
379 sysname_ns =
"boost::units::" + sysname +
"::system";
380 else if (sysname ==
"boost::units::si" || sysname ==
"boost::units::cgs")
381 sysname_ns = sysname +
"::system";
382 else if (sysname ==
"temperature::celsius" || sysname ==
"temperature::fahrenheit")
383 sysname_ns = boost::replace_all_copy(sysname,
"temperature::",
"boost::units::");
384 else if (sysname ==
"angle::degree" || sysname ==
"angle::gradian" ||
385 sysname ==
"angle::revolution")
386 sysname_ns = boost::replace_all_copy(sysname,
"angle::",
"boost::units::") +
"::system";
387 else if (sysname ==
"angle::radian")
388 sysname_ns =
"boost::units::si::system";
390 sysname_ns = sysname;
395 if (absolute && !prefix.empty())
396 throw(std::runtime_error(
397 std::string(
"'prefix' is not supported with an absolute temperature field")));
400 add_absolute(before, after);
403 add_prefix(prefix, before, after);
406 os <<
"typedef " << before <<
"boost::units::unit<" << fieldname <<
"_dimension," << sysname_ns
407 <<
"> " << after << fieldname <<
"_unit;" << std::endl;
412 inline void construct_base_dims_typedef(
const std::vector<std::string>& dim_vec,
413 const std::vector<double>& power_vec,
414 const std::string& fieldname,
const std::string& sysname,
415 const bool& rel_temperature,
const std::string& prefix,
419 bool temperature_dimension =
false;
420 if (dim_vec[0] ==
"temperature" && dim_vec.size() == 1)
421 temperature_dimension =
true;
422 if (dim_vec[0] ==
"dimensionless" && dim_vec.size() == 1)
424 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
430 os <<
"typedef boost::units::derived_dimension< ";
431 for (std::size_t i = 0, n = dim_vec.size(); i < n; i++)
433 os <<
"boost::units::" << dim_vec[i] <<
"_base_dimension," << power_vec[i];
434 if (i != dim_vec.size() - 1)
437 os <<
" >::type " << fieldname <<
"_dimension;" << std::endl;
441 construct_units_typedef_from_dimension(fieldname, sysname,
442 temperature_dimension && !rel_temperature, prefix, os);
446 inline void construct_derived_dims_typedef(
const std::vector<std::string>& dim_vec,
447 const std::vector<std::string>& operator_vec,
448 const std::string& fieldname,
const std::string& sysname,
449 const bool& rel_temperature,
const std::string& prefix,
454 bool temperature_dimension =
false;
456 if (dim_vec.size() == 1)
458 if (dim_vec[0] ==
"temperature")
459 temperature_dimension =
true;
460 if (dim_vec[0] ==
"dimensionless")
461 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
464 os <<
"typedef boost::units::" << dim_vec[0] <<
"_dimension " << fieldname
465 <<
"_dimension;" << std::endl;
472 std::string result = dim_vec[0];
473 for (std::size_t i = 0, n = operator_vec.size(); i < n; i++)
475 if (operator_vec[i] ==
"/")
476 result =
"boost::mpl::divides<boost::units::" + result +
477 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
478 else if (operator_vec[i] ==
"*")
479 result =
"boost::mpl::times<boost::units::" + result +
480 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
482 os << result <<
" " << fieldname <<
"_dimension;" << std::endl;
486 construct_units_typedef_from_dimension(fieldname, sysname,
487 temperature_dimension && !rel_temperature, prefix, os);
494 inline void construct_units_typedef_from_base_unit(
const std::string& fieldname,
495 const std::string& base_unit_category_and_name,
496 const bool& rel_temperature,
497 const std::string& prefix, std::ostream& os)
499 bool temperature_unit =
false;
502 if ((base_unit_category_and_name.find(
"temperature") != std::string::npos) ||
503 (base_unit_category_and_name.find(
"kelvin") != std::string::npos))
504 temperature_unit =
true;
506 bool absolute = temperature_unit && !rel_temperature;
511 add_absolute(before, after);
514 add_prefix(prefix, before, after);
517 os <<
"typedef " << before <<
"boost::units::" << base_unit_category_and_name
518 <<
"_base_unit::unit_type " << after << fieldname <<
"_unit;" << std::endl;
525 inline void construct_field_class_plugin(
const std::string& fieldname, std::ostream& os,
526 const std::string& value_type,
bool is_repeated)
531 os <<
"template<typename Quantity >" << std::endl;
532 os <<
" void set_" << fieldname <<
"_with_units(";
535 os <<
"Quantity value_w_units)" << std::endl;
536 os <<
" { set_" << fieldname <<
"(";
539 os <<
"boost::units::quantity<" << fieldname <<
"_unit," << value_type
540 <<
" >(value_w_units).value() ); };" << std::endl;
545 os <<
"template<typename Quantity >" << std::endl;
546 os <<
" void add_" << fieldname <<
"_with_units(Quantity value_w_units)" << std::endl;
547 os <<
" { add_" << fieldname <<
"(boost::units::quantity<" << fieldname <<
"_unit,"
548 << value_type <<
" >(value_w_units).value() ); };" << std::endl;
553 os <<
"template<typename Quantity >" << std::endl;
554 os <<
" Quantity " << fieldname <<
"_with_units(";
557 os <<
") const" << std::endl;
558 os <<
" { return Quantity(" << fieldname <<
"(";
561 os <<
") * " << fieldname <<
"_unit()); };" << std::endl;
565 os <<
"boost::units::quantity< " << fieldname <<
"_unit," << value_type <<
" > " << fieldname
569 os <<
") const" << std::endl;
570 os <<
" { return " << fieldname <<
"_with_units<boost::units::quantity< " << fieldname
571 <<
"_unit," << value_type <<
" > >(";
574 os <<
"); };" << std::endl;