25 #ifndef GenUnitsClassPlugin20150310H
26 #define GenUnitsClassPlugin20150310H
28 #include <google/protobuf/descriptor.h>
30 #include <boost/config/warning_disable.hpp>
31 #include <boost/lambda/lambda.hpp>
32 #include <boost/spirit/include/phoenix_bind.hpp>
33 #include <boost/spirit/include/phoenix_core.hpp>
34 #include <boost/spirit/include/phoenix_operator.hpp>
35 #include <boost/spirit/include/phoenix_stl.hpp>
36 #include <boost/spirit/include/qi.hpp>
37 #include <boost/spirit/include/qi_expect.hpp>
38 #include <boost/spirit/include/qi_lit.hpp>
40 #include <boost/algorithm/string/replace.hpp>
47 #include <boost/bimap.hpp>
58 namespace qi = boost::spirit::qi;
59 namespace ascii = boost::spirit::ascii;
60 namespace phoenix = boost::phoenix;
63 inline boost::bimap<std::string, char> make_dim_bimap()
65 typedef boost::bimap<std::string, char> dim_bimap;
66 using dimension = dim_bimap::value_type;
69 dims.insert(dimension(
"length",
'L'));
70 dims.insert(dimension(
"time",
'T'));
71 dims.insert(dimension(
"mass",
'M'));
72 dims.insert(dimension(
"plane_angle",
'A'));
73 dims.insert(dimension(
"solid_angle",
'S'));
74 dims.insert(dimension(
"current",
'I'));
75 dims.insert(dimension(
"temperature",
'K'));
76 dims.insert(dimension(
"amount",
'N'));
77 dims.insert(dimension(
"luminous_intensity",
'J'));
78 dims.insert(dimension(
"information",
'B'));
79 dims.insert(dimension(
"dimensionless",
'-'));
85 inline void push_char_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
88 vc.emplace_back(1, c);
90 using bimap_type = boost::bimap<std::string, char>;
91 bimap_type dim_bimap = make_dim_bimap();
93 bimap_type::right_const_iterator it_right = dim_bimap.right.find(c);
95 vs.push_back(it_right->second);
99 inline void push_string_base(std::vector<std::string>& vc, std::vector<std::string>& vs,
100 const std::string& s)
104 using bimap_type = boost::bimap<std::string, char>;
105 bimap_type dim_bimap = make_dim_bimap();
107 bimap_type::left_const_iterator it_left = dim_bimap.left.find(s);
109 vc.emplace_back(1, it_left->second);
113 inline void push_char(std::vector<std::string>& vc,
const char& c) { vc.emplace_back(1, c); }
116 inline void push_char_vec(std::vector<std::string>& vc,
const std::vector<char>& c)
118 vc.emplace_back(c.begin(), c.end());
122 template <
typename Iterator>
123 bool parse_base_dimensions(Iterator first, Iterator last, std::vector<double>& base_dim_powers,
124 std::vector<std::string>& base_dim_chars,
125 std::vector<std::string>& base_dim_strings)
132 using phoenix::push_back;
137 using qi::phrase_parse;
141 bool r = phrase_parse(
144 +((char_(
"LTMASIKNJB-")[phoenix::bind(&push_char_base, phoenix::ref(base_dim_chars),
145 phoenix::ref(base_dim_strings), _1)] |
146 ((ascii::string(
"length") | ascii::string(
"time") | ascii::string(
"mass") |
147 ascii::string(
"plane_angle") | ascii::string(
"solid_angle") |
148 ascii::string(
"current") | ascii::string(
"temperature") | ascii::string(
"amount") |
149 ascii::string(
"luminous_intensity") | ascii::string(
"information") |
150 ascii::string(
"dimensionless"))[phoenix::bind(
151 &push_string_base, phoenix::ref(base_dim_chars), phoenix::ref(base_dim_strings),
153 -(ascii::string(
"_base_dimension")) >>
154 ((
'^' > double_[push_back(phoenix::ref(base_dim_powers), _1)]) |
155 eps[push_back(phoenix::ref(base_dim_powers), 1)])),
163 catch (
const std::runtime_error& e)
170 template <
typename Iterator>
171 bool parse_derived_dimensions(Iterator first, Iterator last,
172 std::vector<std::string>& derived_dim_operators,
173 std::vector<std::string>& derived_dim_strings)
176 using phoenix::push_back;
181 using qi::phrase_parse;
185 std::vector<std::string> params;
186 bool r = boost::spirit::qi::parse(
188 +((+char_(
"a-z1_"))[phoenix::bind(&push_char_vec, boost::phoenix::ref(params), _1)] >>
190 (char_(
"*/")[phoenix::bind(&push_char, phoenix::ref(derived_dim_operators), _1)] |
191 eps[push_back(phoenix::ref(derived_dim_operators), std::string(
"*"))]) >>
194 if (derived_dim_operators.size())
195 derived_dim_operators.pop_back();
197 for (
auto& param : params)
199 std::string::size_type dim_pos = param.find(
"_dimension");
200 if (dim_pos != std::string::npos)
201 param = param.substr(0, dim_pos);
203 derived_dim_strings.push_back(param);
210 catch (
const std::runtime_error& e)
217 inline std::string get_field_type_name(google::protobuf::FieldDescriptor::CppType type)
221 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
return "google::protobuf::int32";
222 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
return "google::protobuf::int64";
223 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
return "google::protobuf::uint32";
224 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
return "google::protobuf::uint64";
225 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
return "double";
226 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
return "float";
227 default:
return "double";
248 inline void include_units_headers(
const std::string& sysname, std::ostream& os)
258 if (sysname ==
"si" || sysname ==
"boost::units::si" || sysname ==
"angle::radian")
260 os <<
"#include <boost/units/systems/si.hpp>" << std::endl;
262 else if (sysname ==
"cgs" || sysname ==
"boost::units::cgs")
264 os <<
"#include <boost/units/systems/cgs.hpp>" << std::endl;
266 else if (sysname ==
"celsius" || sysname ==
"boost::units::celsius" ||
267 sysname ==
"temperature::celsius")
269 os <<
"#include <boost/units/systems/temperature/celsius.hpp>" << std::endl;
271 else if (sysname ==
"fahrenheit" || sysname ==
"boost::units::fahrenheit" ||
272 sysname ==
"temperature::fahrenheit")
274 os <<
"#include <boost/units/systems/temperature/fahrenheit.hpp>" << std::endl;
276 else if (sysname ==
"degree" || sysname ==
"boost::units::degree" || sysname ==
"angle::degree")
278 os <<
"#include <boost/units/systems/angle/degrees.hpp>" << std::endl;
280 else if (sysname ==
"gradian" || sysname ==
"boost::units::gradian" ||
281 sysname ==
"angle::gradian")
283 os <<
"#include <boost/units/systems/angle/gradians.hpp>" << std::endl;
285 else if (sysname ==
"revolution" || sysname ==
"boost::units::revolution" ||
286 sysname ==
"angle::revolution")
288 os <<
"#include <boost/units/systems/angle/revolutions.hpp>" << std::endl;
293 std::string sysname_sub = boost::replace_all_copy(sysname,
"::",
"/");
294 os <<
"#include \"" << sysname_sub <<
".hpp\"" << std::endl;
301 inline void include_base_unit_headers(
const std::string& base_unit_category_and_name,
305 std::string cat_name_sub = boost::replace_all_copy(base_unit_category_and_name,
"::",
"/");
306 os <<
"#include <boost/units/base_units/" << cat_name_sub <<
".hpp>" << std::endl;
309 inline void add_absolute(std::string& before, std::string& after)
311 before =
"boost::units::absolute<" + before;
315 inline void add_prefix(
const std::string& prefix, std::string& before, std::string& after)
318 if (prefix ==
"yotta")
320 else if (prefix ==
"zetta")
322 else if (prefix ==
"exa")
324 else if (prefix ==
"peta")
326 else if (prefix ==
"tera")
328 else if (prefix ==
"giga")
330 else if (prefix ==
"mega")
332 else if (prefix ==
"kilo")
334 else if (prefix ==
"hecto")
336 else if (prefix ==
"deka")
338 else if (prefix ==
"deci")
340 else if (prefix ==
"centi")
342 else if (prefix ==
"milli")
344 else if (prefix ==
"micro")
346 else if (prefix ==
"nano")
348 else if (prefix ==
"pico")
350 else if (prefix ==
"femto")
352 else if (prefix ==
"atto")
354 else if (prefix ==
"zepto")
356 else if (prefix ==
"yocto")
359 throw(std::runtime_error(std::string(
"Invalid SI prefix: " + prefix)));
361 std::stringstream power_ss;
364 before =
"boost::units::make_scaled_unit<" + before;
365 after +=
", boost::units::scale<10, boost::units::static_rational<" + power_ss.str() +
370 inline void construct_units_typedef_from_dimension(
const std::string& fieldname,
371 const std::string& sysname,
const bool& absolute,
372 const std::string& prefix, std::ostream& os)
375 std::string sysname_ns;
376 if (sysname ==
"si" || sysname ==
"cgs" || sysname ==
"celsius" || sysname ==
"fahrenheit" ||
377 sysname ==
"degree" || sysname ==
"gradian" || sysname ==
"revolution")
378 sysname_ns =
"boost::units::" + sysname +
"::system";
379 else if (sysname ==
"boost::units::si" || sysname ==
"boost::units::cgs")
380 sysname_ns = sysname +
"::system";
381 else if (sysname ==
"temperature::celsius" || sysname ==
"temperature::fahrenheit")
382 sysname_ns = boost::replace_all_copy(sysname,
"temperature::",
"boost::units::");
383 else if (sysname ==
"angle::degree" || sysname ==
"angle::gradian" ||
384 sysname ==
"angle::revolution")
385 sysname_ns = boost::replace_all_copy(sysname,
"angle::",
"boost::units::") +
"::system";
386 else if (sysname ==
"angle::radian")
387 sysname_ns =
"boost::units::si::system";
389 sysname_ns = sysname;
394 if (absolute && !prefix.empty())
395 throw(std::runtime_error(
396 std::string(
"'prefix' is not supported with an absolute temperature field")));
399 add_absolute(before, after);
402 add_prefix(prefix, before, after);
405 os <<
"typedef " << before <<
"boost::units::unit<" << fieldname <<
"_dimension," << sysname_ns
406 <<
"> " << after << fieldname <<
"_unit;" << std::endl;
411 inline void construct_base_dims_typedef(
const std::vector<std::string>& dim_vec,
412 const std::vector<double>& power_vec,
413 const std::string& fieldname,
const std::string& sysname,
414 const bool& rel_temperature,
const std::string& prefix,
418 bool temperature_dimension =
false;
419 if (dim_vec[0] ==
"temperature" && dim_vec.size() == 1)
420 temperature_dimension =
true;
421 if (dim_vec[0] ==
"dimensionless" && dim_vec.size() == 1)
423 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
429 os <<
"typedef boost::units::derived_dimension< ";
430 for (std::size_t i = 0, n = dim_vec.size(); i < n; i++)
432 os <<
"boost::units::" << dim_vec[i] <<
"_base_dimension," << power_vec[i];
433 if (i != dim_vec.size() - 1)
436 os <<
" >::type " << fieldname <<
"_dimension;" << std::endl;
440 construct_units_typedef_from_dimension(fieldname, sysname,
441 temperature_dimension && !rel_temperature, prefix, os);
445 inline void construct_derived_dims_typedef(
const std::vector<std::string>& dim_vec,
446 const std::vector<std::string>& operator_vec,
447 const std::string& fieldname,
const std::string& sysname,
448 const bool& rel_temperature,
const std::string& prefix,
453 bool temperature_dimension =
false;
455 if (dim_vec.size() == 1)
457 if (dim_vec[0] ==
"temperature")
458 temperature_dimension =
true;
459 if (dim_vec[0] ==
"dimensionless")
460 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
463 os <<
"typedef boost::units::" << dim_vec[0] <<
"_dimension " << fieldname
464 <<
"_dimension;" << std::endl;
471 std::string result = dim_vec[0];
472 for (std::size_t i = 0, n = operator_vec.size(); i < n; i++)
474 if (operator_vec[i] ==
"/")
475 result =
"boost::mpl::divides<boost::units::" + result +
476 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
477 else if (operator_vec[i] ==
"*")
478 result =
"boost::mpl::times<boost::units::" + result +
479 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
481 os << result <<
" " << fieldname <<
"_dimension;" << std::endl;
485 construct_units_typedef_from_dimension(fieldname, sysname,
486 temperature_dimension && !rel_temperature, prefix, os);
493 inline void construct_units_typedef_from_base_unit(
const std::string& fieldname,
494 const std::string& base_unit_category_and_name,
495 const bool& rel_temperature,
496 const std::string& prefix, std::ostream& os)
498 bool temperature_unit =
false;
501 if ((base_unit_category_and_name.find(
"temperature") != std::string::npos) ||
502 (base_unit_category_and_name.find(
"kelvin") != std::string::npos))
503 temperature_unit =
true;
505 bool absolute = temperature_unit && !rel_temperature;
510 add_absolute(before, after);
513 add_prefix(prefix, before, after);
516 os <<
"typedef " << before <<
"boost::units::" << base_unit_category_and_name
517 <<
"_base_unit::unit_type " << after << fieldname <<
"_unit;" << std::endl;
524 inline void construct_field_class_plugin(
const std::string& fieldname, std::ostream& os,
525 const std::string& value_type,
bool is_repeated)
530 os <<
"template<typename Quantity >" << std::endl;
531 os <<
" void set_" << fieldname <<
"_with_units(";
534 os <<
"Quantity value_w_units)" << std::endl;
535 os <<
" { set_" << fieldname <<
"(";
538 os <<
"boost::units::quantity<" << fieldname <<
"_unit," << value_type
539 <<
" >(value_w_units).value() ); };" << std::endl;
544 os <<
"template<typename Quantity >" << std::endl;
545 os <<
" void add_" << fieldname <<
"_with_units(Quantity value_w_units)" << std::endl;
546 os <<
" { add_" << fieldname <<
"(boost::units::quantity<" << fieldname <<
"_unit,"
547 << value_type <<
" >(value_w_units).value() ); };" << std::endl;
552 os <<
"template<typename Quantity >" << std::endl;
553 os <<
" Quantity " << fieldname <<
"_with_units(";
556 os <<
") const" << std::endl;
557 os <<
" { return Quantity(" << fieldname <<
"(";
560 os <<
") * " << fieldname <<
"_unit()); };" << std::endl;
564 os <<
"boost::units::quantity< " << fieldname <<
"_unit," << value_type <<
" > " << fieldname
568 os <<
") const" << std::endl;
569 os <<
" { return " << fieldname <<
"_with_units<boost::units::quantity< " << fieldname
570 <<
"_unit," << value_type <<
" > >(";
573 os <<
"); };" << std::endl;