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 add_absolute(std::string& before, std::string& after)
 
  312    before = 
"boost::units::absolute<" + before;
 
  316inline 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() +
 
  371inline 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;
 
  412inline 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);
 
  446inline 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);
 
  494inline 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;
 
  525inline 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;
 
Dynamic Compact Control Language namespace.