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;