تعيين البيانات بتنسيق json إلى بنية c ++ والعودة (العمل على الأخطاء)

تحول الإصدار السابق من حل مشكلة رسم الخرائط بين هيكل C ++ و json مثل الفطيرة الأولى - كتلة. لحسن الحظ ، يعد التطوير عملية تكرارية وسيكون هناك دائمًا إصدار ثانٍ خلف الإصدار الأول. التعليقات (شكرا للجميع) وتحليل الثقب في أول فطيرة أدخلت بعض التحسينات.



ما كان سيئا



  • من المستحيل استخدام هياكل C ++ العادية (بما في ذلك تلك الموجودة بالفعل). يجب تحديد جميع الهياكل من نقطة الصفر بطريقة خاصة
  • يمكن تعيين كائن Json فقط إلى بنية محددة بشكل خاص
  • يمكن تعيين صفيف Json فقط إلى فئة خاصة
  • من المستحيل استخدام حاويات STL
  • وحدات الماكرو ضرورية ببساطة (من الممكن بدونها ، ولكن يتم تسجيل تسجيل طرق تعيين الحقول بشكل صارم مع تهيئة هذه الحقول ، وبالتالي ، بدون وحدات الماكرو ، فإن تعريف البنية غير قابل للقراءة)
  • العرض غير قابل للتكوين بأي شكل من الأشكال ؛ لا يمكن تعيين ، على سبيل المثال ، القيم الافتراضية أو حدود القيمة


كيف أصبحت الآن



لم يعد تسجيل الحقول التي ستشارك في العرض مرتبطًا بالبنية. للتسجيل ، استخدم الوظيفة



reg(V T::* ptr, std::string const & name, Options<U>&& ... options);


  • ptr - مؤشر المجال
  • name - اسم الحقل
  • options - خيارات العرض


يمكن استخدام ما يلي كأنواع حقول:



  • منطقية
  • حرف ، حرف غير موقع ، قصير ، غير موقع قصير ، int غير موقع int ، طويل ، طويل طويل
  • تعويم ، مزدوج
  • الأمراض المنقولة جنسيا :: سلسلة
  • الأمراض المنقولة جنسيا :: list
  • الأمراض المنقولة جنسيا :: ناقلات
  • std::map ( std::string)
  • std::unordered_map ( std::string)
  • std::multimap ( std::string)
  • std::unordered_multimap ( std::string)
  • ++




struct Friend {
 std::string name;
 std::list<int> counters;
};

struct MiB {
 std::list<Friend> friends;
 std::vector<std::list<std::string>> groups;
 std::map<std::string, std::vector<std::string>> books;
};

struct_mapping::reg(&Friend::name, "name");
struct_mapping::reg(&Friend::counters, "counters");

struct_mapping::reg(&MiB::friends, "friends");
struct_mapping::reg(&MiB::groups, "groups");
struct_mapping::reg(&MiB::books, "books");


, ,



map_json_to_struct(T & result_struct, std::basic_istream<char> & json_data);


  • result_struct
  • json_data — json


. .





#include <iostream>
#include <sstream>

#include "struct_mapping/struct_mapping.h"

struct Planet {
 bool giant;
 long long surface_area;
 double mass;
 std::string satellite;
};

int main() {
 struct_mapping::reg(&Planet::giant, "giant");
 struct_mapping::reg(&Planet::surface_area, "surface_area");
 struct_mapping::reg(&Planet::mass, "mass");
 struct_mapping::reg(&Planet::satellite, "satellite");

 Planet earth;

 std::istringstream json_data(R"json(
  {
   "giant": false,
   "surface_area": 510072000000000,
   "mass": 5.97237e24,
   "satellite": "Moon"
  }
 )json");

 struct_mapping::map_json_to_struct(earth, json_data);

 std::cout << "earth" << std::endl;
 std::cout << " giant        : " << std::boolalpha << earth.giant << std::endl;
 std::cout << " surface_area : " << earth.surface_area << std::endl;
 std::cout << " mass         : " << earth.mass << std::endl;
 std::cout << " satellite    : " << earth.satellite << std::endl;
}




earth
 giant        : false
 surface_area : 510072000000000
 mass         : 5.97237e+24
 satellite    : Moon




, json . , :



MemberString::set(From function_from_string_, To function_to_string_);


  • function_from_string_
  • function_to_string_




enum class Color {
 red,
 blue,
 green,
};

struct_mapping::MemberString<Color>::set(
 [] (const std::string & value) {
  if (value == "red") return Color::red;
  if (value == "green") return Color::green;
  if (value == "blue") return Color::blue;

  throw struct_mapping::StructMappingException("bad convert '"+value+"' to Color");
 },
 [] (Color value) {
  switch (value) {
  case Color::red: return "red";
  case Color::green: return "green";
  default: return "blue";
  }
 });




#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>

#include "struct_mapping/struct_mapping.h"

namespace sm = struct_mapping;

enum class Color {
 red,
 blue,
 green,
};

Color color_from_string(const std::string & value) {
 if (value == "red") return Color::red;
 if (value == "blue") return Color::blue;

 return Color::green;
}

std::string color_to_string(Color color) {
 switch (color) {
 case Color::red: return "red";
 case Color::green: return "green";
 default: return "blue";
 }
}

struct Palette {
 Color main_color;
 Color background_color;
 std::list<Color> special_colors;
 std::map<std::string, Color> colors;

 friend std::ostream & operator<<(std::ostream & os, const Palette & o) {
  os << "main_color       : " << color_to_string(o.main_color) << std::endl;
  os << "background_color : " << color_to_string(o.background_color) << std::endl;
  os << "special_colors   : ";
  for (auto color : o.special_colors)
   os << color_to_string(color) << ", ";
  os << std::endl << "colors           : ";
  for (auto [name, color] : o.colors)
   os << "[" << name << ", " << color_to_string(color) << "], ";
  os << std::endl;

  return os;
 }
};

int main() {
 sm::MemberString<Color>::set(color_from_string, color_to_string);

 sm::reg(&Palette::main_color, "main_color", sm::Required{});
 sm::reg(&Palette::background_color, "background_color", sm::Default{Color::blue});
 sm::reg(&Palette::special_colors, "special_colors");
 sm::reg(&Palette::colors, "colors");

 Palette palette;

 std::istringstream json_data(R"json(
 {
  "main_color": "green",
  "special_colors": ["green", "green", "red"],
  "colors": {
   "dark": "green",
   "light": "red",
   "neutral": "blue"
  }
 }
 )json");

 sm::map_json_to_struct(palette, json_data);

 std::cout << palette << std::endl;
}




main_color       : green
background_color : blue
special_colors   : green, green, red, 
colors           : [dark, green], [light, red], [neutral, blue],




,



  • Bounds
  • Default
  • NotEmpty
  • Required


Bounds



, ( ) . . — . .



Bounds{ ,  }


:



reg(&Stage::engine_count, "engine_count", Bounds{1, 31});


Default



. bool, , , , , ++ . — .



Default{  }


:



reg(&Stage::engine_count, "engine_count", Default{3});


NotEmpty



, . . . , .



:



reg(&Spacecraft::name, "name", NotEmpty{}));


Required



, . bool, , , , , ++ . . , .



:



reg(&Spacecraft::name, "name", Required{}));




#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>

#include "struct_mapping/struct_mapping.h"

namespace sm = struct_mapping;

struct Stage {
 unsigned short engine_count;
 std::string fuel;
 long length;

 friend std::ostream & operator<<(std::ostream & os, const Stage & o) {
  os << "  engine_count : " << o.engine_count << std::endl;
  os << "  fuel         : " << o.fuel << std::endl;
  os << "  length       : " << o.length << std::endl;

  return os;
 }
};

struct Spacecraft {
 bool in_development;
 std::string name;
 int mass;
 std::map<std::string, Stage> stages;
 std::list<std::string> crew;

 friend std::ostream & operator<<(std::ostream & os, const Spacecraft & o) {
  os << "in_development : " << std::boolalpha << o.in_development << std::endl;
  os << "name           : " << o.name << std::endl;
  os << "mass           : " << o.mass << std::endl;
  os << "stages: " << std::endl;
  for (auto& s : o.stages) os << " " << s.first << std::endl << s.second;
  os << "crew: " << std::endl;
  for (auto& p : o.crew) os << " " << p << std::endl;

  return os;
 }
};

int main() {
 sm::reg(&Stage::engine_count, "engine_count", sm::Default{6}, sm::Bounds{1, 31});
 sm::reg(&Stage::fuel, "fuel", sm::Default{"subcooled"});
 sm::reg(&Stage::length, "length", sm::Default{50});

 sm::reg(&Spacecraft::in_development, "in_development", sm::Required{});
 sm::reg(&Spacecraft::name, "name", sm::NotEmpty{});
 sm::reg(&Spacecraft::mass, "mass",
  sm::Default{5000000}, sm::Bounds{100000, 10000000});
 sm::reg(&Spacecraft::stages, "stages", sm::NotEmpty{});
 sm::reg(&Spacecraft::crew, "crew",
  sm::Default{std::list<std::string>{"Arthur", "Ford", "Marvin"}});

 Spacecraft starship;

 std::istringstream json_data(R"json(
 {
  "in_development": false,
  "name": "Vostok",
  "stages": {
   "first": {
    "engine_count": 31,
    "fuel": "compressed gas",
    "length": 70
   },
   "second": {}
  }
 }
 )json");

 sm::map_json_to_struct(starship, json_data);

 std::cout << starship << std::endl;
}




in_development : false
name           : Vostok
mass           : 5000000
stages: 
 first
  engine_count : 31
  fuel         : compressed gas
  length       : 70
 second
  engine_count : 6
  fuel         : subcooled
  length       : 50
crew: 
 Arthur
 Ford
 Marvin


c++ json



json , ,



reg(V T::* ptr, std::string const & name, Options<U>&& ... options);




map_struct_to_json(T & source_struct, std::basic_ostream<char> & json_data, std::string indent);


  • source_struct
  • json_data — json
  • indent — ( , )


#include <iostream>
#include <sstream>

#include "struct_mapping/struct_mapping.h"

struct OceanPart {
 std::string name;
 double average_depth;
 std::vector<int> temperature;
};

struct OceanColor {
 std::string name;
};

struct Ocean {
 double water_volume;
 long long surface_area;
 bool liquid;
 std::string name;

 OceanColor color;

 std::vector<OceanPart> parts;
};

struct Planet {
 bool giant;
 long long surface_area;
 double mass;
 double volume;
 long long orbital_period;
 std::string name;
 bool terrestrial;
 std::string shape;

 Ocean ocean;
};

int main() {
 struct_mapping::reg(&OceanPart::name, "name");
 struct_mapping::reg(&OceanPart::average_depth, "average_depth");
 struct_mapping::reg(&OceanPart::temperature, "temperature");

 struct_mapping::reg(&OceanColor::name, "name");

 struct_mapping::reg(&Ocean::water_volume, "water_volume");
 struct_mapping::reg(&Ocean::surface_area, "surface_area");
 struct_mapping::reg(&Ocean::liquid, "liquid");
 struct_mapping::reg(&Ocean::name, "name");
 struct_mapping::reg(&Ocean::color, "color");
 struct_mapping::reg(&Ocean::parts, "parts");

 struct_mapping::reg(&Planet::giant, "giant");
 struct_mapping::reg(&Planet::surface_area, "surface_area");
 struct_mapping::reg(&Planet::mass, "mass");
 struct_mapping::reg(&Planet::volume, "volume");
 struct_mapping::reg(&Planet::orbital_period, "orbital_period");
 struct_mapping::reg(&Planet::name, "name");
 struct_mapping::reg(&Planet::terrestrial, "terrestrial");
 struct_mapping::reg(&Planet::shape, "shape");
 struct_mapping::reg(&Planet::ocean, "ocean");

 Planet earth;

 earth.giant = false;
 earth.terrestrial = true;
 earth.surface_area = 510072000;
 earth.orbital_period = 365 * 24 * 3600;
 earth.mass = 5.97237e24;
 earth.name = "Terra";
 earth.volume = 1.08321e12;
 earth.shape = "nearly spherical";

 earth.ocean.water_volume = 1332000000;
 earth.ocean.surface_area = 361132000;
 earth.ocean.liquid = true;
 earth.ocean.name = "World Ocean";
 earth.ocean.color.name = "blue";

 OceanPart pacific;
 pacific.name = "Pacific Ocean";
 pacific.average_depth = 4.280111;
 pacific.temperature = std::vector<int>{-3, 5, 12};

 OceanPart atlantic;
 atlantic.name = "Atlantic Ocean";
 atlantic.average_depth = 3.646;
 atlantic.temperature = std::vector<int>{-3, 0};

 earth.ocean.parts.push_back(pacific);
 earth.ocean.parts.push_back(atlantic);

 std::ostringstream json_data;
 struct_mapping::map_struct_to_json(earth, json_data, "  ");

 std::cout << json_data.str() << std::endl;
}




{
  "giant": false,
  "surface_area": 510072000,
  "mass": 5.97237e+24,
  "volume": 1.08321e+12,
  "orbital_period": 31536000,
  "name": "Terra",
  "terrestrial": true,
  "shape": "nearly spherical",
  "ocean": {
    "water_volume": 1.332e+09,
    "surface_area": 361132000,
    "liquid": true,
    "name": "World Ocean",
    "color": {
      "name": "blue"
    },
    "parts": [
      {
        "name": "Pacific Ocean",
        "average_depth": 4.28011,
        "temperature": [
          -3,
          5,
          12
        ]
      },
      {
        "name": "Atlantic Ocean",
        "average_depth": 3.646,
        "temperature": [
          -3,
          0
        ]
      }
    ]
  }
}




  • ++ ( )
  • يمكن تعيين كائنات Json على حد سواء إلى بنية محددة بشكل خاص (تبقى هذه الإمكانية) وإلى الهياكل العادية
  • يمكن تعيين صفائف Json إلى std :: vector و std :: list. المتطلبات العامة للحاويات التي يمكن رسم صفائف عليها لم يتم تشكيلها بالكامل بعد.
  • يمكن تعيين كائنات json إلى حاويات ترابطية ، مع تقييد أن المفتاح يجب أن يكون سلسلة. المتطلبات العامة للحاويات ، وكذلك مع المصفوفات ، لم يتم تشكيلها بالكامل بعد.
  • وحدات الماكرو غير ضرورية وبالتأكيد ليست ضرورية. بقيت إمكانية استخدامها (كخيار) أثناء التسجيل ، إلى جانب تهيئة الحقول. ولكن على الأرجح سيتم قطعه.
  • يمكن تخصيص العرض باستخدام الخيارات


المكتبة متاحة على GitHub




All Articles