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>
59namespace qi = boost::spirit::qi;
60namespace ascii = boost::spirit::ascii;
61namespace phoenix = boost::phoenix;
64inline 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",
'-'));
86inline 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);
100inline 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);
114inline void push_char(std::vector<std::string>& vc,
const char& c) { vc.emplace_back(1, c); }
117inline void push_char_vec(std::vector<std::string>& vc,
const std::vector<char>& c)
119 vc.emplace_back(c.begin(), c.end());
123template <
typename Iterator>
124bool 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)
171template <
typename Iterator>
172bool 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)
218inline 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";
249inline 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;
302inline 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;
310inline void include_custom_unit_headers(
const std::string& header, std::ostream& os)
313 os <<
"#include \"" << header <<
"\"" << std::endl;
316inline void add_absolute(std::string& before, std::string& after)
318 before =
"boost::units::absolute<" + before;
322inline void add_prefix(
const std::string& prefix, std::string& before, std::string& after)
325 if (prefix ==
"yotta")
327 else if (prefix ==
"zetta")
329 else if (prefix ==
"exa")
331 else if (prefix ==
"peta")
333 else if (prefix ==
"tera")
335 else if (prefix ==
"giga")
337 else if (prefix ==
"mega")
339 else if (prefix ==
"kilo")
341 else if (prefix ==
"hecto")
343 else if (prefix ==
"deka")
345 else if (prefix ==
"deci")
347 else if (prefix ==
"centi")
349 else if (prefix ==
"milli")
351 else if (prefix ==
"micro")
353 else if (prefix ==
"nano")
355 else if (prefix ==
"pico")
357 else if (prefix ==
"femto")
359 else if (prefix ==
"atto")
361 else if (prefix ==
"zepto")
363 else if (prefix ==
"yocto")
366 throw(std::runtime_error(std::string(
"Invalid SI prefix: " + prefix)));
368 std::stringstream power_ss;
371 before =
"boost::units::make_scaled_unit<" + before;
372 after +=
", boost::units::scale<10, boost::units::static_rational<" + power_ss.str() +
377inline void construct_units_typedef_from_dimension(
const std::string& fieldname,
378 const std::string& sysname,
const bool& absolute,
379 const std::string& prefix, std::ostream& os)
382 std::string sysname_ns;
383 if (sysname ==
"si" || sysname ==
"cgs" || sysname ==
"celsius" || sysname ==
"fahrenheit" ||
384 sysname ==
"degree" || sysname ==
"gradian" || sysname ==
"revolution")
385 sysname_ns =
"boost::units::" + sysname +
"::system";
386 else if (sysname ==
"boost::units::si" || sysname ==
"boost::units::cgs")
387 sysname_ns = sysname +
"::system";
388 else if (sysname ==
"temperature::celsius" || sysname ==
"temperature::fahrenheit")
389 sysname_ns = boost::replace_all_copy(sysname,
"temperature::",
"boost::units::");
390 else if (sysname ==
"angle::degree" || sysname ==
"angle::gradian" ||
391 sysname ==
"angle::revolution")
392 sysname_ns = boost::replace_all_copy(sysname,
"angle::",
"boost::units::") +
"::system";
393 else if (sysname ==
"angle::radian")
394 sysname_ns =
"boost::units::si::system";
396 sysname_ns = sysname;
401 if (absolute && !prefix.empty())
402 throw(std::runtime_error(
403 std::string(
"'prefix' is not supported with an absolute temperature field")));
406 add_absolute(before, after);
409 add_prefix(prefix, before, after);
412 os <<
"typedef " << before <<
"boost::units::unit<" << fieldname <<
"_dimension," << sysname_ns
413 <<
"> " << after << fieldname <<
"_unit;" << std::endl;
418inline void construct_base_dims_typedef(
const std::vector<std::string>& dim_vec,
419 const std::vector<double>& power_vec,
420 const std::string& fieldname,
const std::string& sysname,
421 const bool& rel_temperature,
const std::string& prefix,
425 bool temperature_dimension =
false;
426 if (dim_vec[0] ==
"temperature" && dim_vec.size() == 1)
427 temperature_dimension =
true;
428 if (dim_vec[0] ==
"dimensionless" && dim_vec.size() == 1)
430 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
436 os <<
"typedef boost::units::derived_dimension< ";
437 for (std::size_t i = 0, n = dim_vec.size(); i < n; i++)
439 os <<
"boost::units::" << dim_vec[i] <<
"_base_dimension," << power_vec[i];
440 if (i != dim_vec.size() - 1)
443 os <<
" >::type " << fieldname <<
"_dimension;" << std::endl;
447 construct_units_typedef_from_dimension(fieldname, sysname,
448 temperature_dimension && !rel_temperature, prefix, os);
452inline void construct_derived_dims_typedef(
const std::vector<std::string>& dim_vec,
453 const std::vector<std::string>& operator_vec,
454 const std::string& fieldname,
const std::string& sysname,
455 const bool& rel_temperature,
const std::string& prefix,
460 bool temperature_dimension =
false;
462 if (dim_vec.size() == 1)
464 if (dim_vec[0] ==
"temperature")
465 temperature_dimension =
true;
466 if (dim_vec[0] ==
"dimensionless")
467 os <<
"typedef boost::units::dimensionless_type " << fieldname <<
"_dimension;"
470 os <<
"typedef boost::units::" << dim_vec[0] <<
"_dimension " << fieldname
471 <<
"_dimension;" << std::endl;
478 std::string result = dim_vec[0];
479 for (std::size_t i = 0, n = operator_vec.size(); i < n; i++)
481 if (operator_vec[i] ==
"/")
482 result =
"boost::mpl::divides<boost::units::" + result +
483 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
484 else if (operator_vec[i] ==
"*")
485 result =
"boost::mpl::times<boost::units::" + result +
486 "_dimension,boost::units::" + dim_vec[i + 1] +
"_dimension>::type";
488 os << result <<
" " << fieldname <<
"_dimension;" << std::endl;
492 construct_units_typedef_from_dimension(fieldname, sysname,
493 temperature_dimension && !rel_temperature, prefix, os);
500inline void construct_units_typedef_from_base_unit(
const std::string& fieldname,
501 const std::string& base_unit_category_and_name,
502 const bool& rel_temperature,
503 const std::string& prefix, std::ostream& os)
505 bool temperature_unit =
false;
508 if ((base_unit_category_and_name.find(
"temperature") != std::string::npos) ||
509 (base_unit_category_and_name.find(
"kelvin") != std::string::npos))
510 temperature_unit =
true;
512 bool absolute = temperature_unit && !rel_temperature;
517 add_absolute(before, after);
520 add_prefix(prefix, before, after);
523 os <<
"typedef " << before <<
"boost::units::" << base_unit_category_and_name
524 <<
"_base_unit::unit_type " << after << fieldname <<
"_unit;" << std::endl;
531inline void construct_units_typedef_from_custom_unit(
const std::string& fieldname,
532 const std::string& unit_name,
533 const bool& rel_temperature,
534 const std::string& prefix, std::ostream& os)
536 bool temperature_unit =
false;
539 if ((unit_name.find(
"temperature") != std::string::npos) ||
540 (unit_name.find(
"kelvin") != std::string::npos))
541 temperature_unit =
true;
543 bool absolute = temperature_unit && !rel_temperature;
548 add_absolute(before, after);
551 add_prefix(prefix, before, after);
554 os <<
"typedef " << before << unit_name <<
" " << after << fieldname <<
"_unit;" << std::endl;
560inline void construct_field_class_plugin(
const std::string& fieldname, std::ostream& os,
561 const std::string& value_type,
bool is_repeated)
566 os <<
"template<typename Quantity >" << std::endl;
567 os <<
" void set_" << fieldname <<
"_with_units(";
570 os <<
"Quantity value_w_units)" << std::endl;
571 os <<
" { set_" << fieldname <<
"(";
574 os <<
"boost::units::quantity<" << fieldname <<
"_unit," << value_type
575 <<
" >(value_w_units).value() ); };" << std::endl;
580 os <<
"template<typename Quantity >" << std::endl;
581 os <<
" void add_" << fieldname <<
"_with_units(Quantity value_w_units)" << std::endl;
582 os <<
" { add_" << fieldname <<
"(boost::units::quantity<" << fieldname <<
"_unit,"
583 << value_type <<
" >(value_w_units).value() ); };" << std::endl;
588 os <<
"template<typename Quantity >" << std::endl;
589 os <<
" Quantity " << fieldname <<
"_with_units(";
592 os <<
") const" << std::endl;
593 os <<
" { return Quantity(" << fieldname <<
"(";
596 os <<
") * " << fieldname <<
"_unit()); };" << std::endl;
600 os <<
"boost::units::quantity< " << fieldname <<
"_unit," << value_type <<
" > " << fieldname
604 os <<
") const" << std::endl;
605 os <<
" { return " << fieldname <<
"_with_units<boost::units::quantity< " << fieldname
606 <<
"_unit," << value_type <<
" > >(";
609 os <<
"); };" << std::endl;
Dynamic Compact Control Language namespace.