Advertisement
Guest User

JSON black belt

a guest
Aug 25th, 2019
240
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.01 KB | None | 0 0
  1. #include <cassert>
  2. #include <cmath>
  3. #include <stdexcept>
  4. #include <sstream>
  5. #include <stack>
  6. #include <string>
  7. #include <optional>
  8. #include <memory>
  9. #include <unordered_map>
  10. #include <variant>
  11.  
  12. #include "test_runner.h"
  13.  
  14. using namespace std;
  15.  
  16. void PrintJsonString(std::ostream &out, std::string_view str)
  17. {
  18.   string str_formatted(str);
  19.   for(size_t i = 0; i < str_formatted.length(); i++)
  20.   {
  21.     if(str[i] == '"' || str[i] == '\\')
  22.     {
  23.         str = str_formatted.insert(i,"\\");
  24.         i++;        
  25.     }    
  26.   }
  27.   out << str_formatted;
  28. }
  29.  
  30. class NoneContext
  31. {
  32.   public:
  33.   NoneContext(ostream& out,
  34.               bool render_start_symbol = true,
  35.               bool render_stop_symbol = true,
  36.               bool render_null_value = true){};
  37. };
  38.  
  39. template<typename Ancestor>
  40. class ArrayContext;
  41.  
  42. template<typename Ancestor>
  43. class ObjectKeyContext;
  44.  
  45. template<typename Ancestor>
  46. class ObjectValueContext;
  47.  
  48. class AbstractContext
  49. {
  50.   public:
  51.     AbstractContext(ostream& out,
  52.                     bool render_start_symbol = true,
  53.                     bool render_stop_symbol = true,
  54.                     bool render_null_value = true) :
  55.                     out_(out),
  56.                     render_start_symbol_(render_start_symbol),
  57.                     render_stop_symbol_(render_stop_symbol),
  58.                     render_null_value_(render_null_value){}
  59.        
  60.     void WriteNumber(int64_t);
  61.     void WriteString(std::string_view);
  62.     void WriteBoolean(bool);
  63.     void WriteNull();
  64.  
  65.   protected:
  66.     void InsertDelimeter_();
  67.     ostream& out_;
  68.     bool render_start_symbol_;
  69.     bool render_stop_symbol_;
  70.     bool render_null_value_;
  71.  
  72. };
  73.  
  74. template<typename Ancestor>
  75. class ArrayContext : public AbstractContext
  76. {
  77.   public:
  78.     ArrayContext(std::ostream &out,
  79.                  bool render_start_symbol = true,
  80.                  bool render_stop_symbol = true,
  81.                  bool render_null_value = true);
  82.     ~ArrayContext();
  83.  
  84.     ArrayContext<Ancestor>& Number(int64_t);
  85.     ArrayContext<Ancestor>& String(std::string_view);
  86.     ArrayContext<Ancestor>& Boolean(bool);
  87.     ArrayContext<Ancestor>& Null();
  88.    
  89.     ArrayContext<ArrayContext<Ancestor>> BeginArray();
  90.     Ancestor EndArray();
  91.     ObjectKeyContext<ArrayContext<Ancestor>> BeginObject();
  92.  
  93. };
  94.  
  95. ArrayContext<NoneContext> PrintJsonArray(std::ostream &out)
  96. {
  97.   return ArrayContext<NoneContext>(out);
  98. }
  99.  
  100. template<typename Ancestor>
  101. ArrayContext<Ancestor>::ArrayContext(std::ostream &out,
  102.                                      bool render_start_symbol,
  103.                                      bool render_stop_symbol,
  104.                                      bool render_null_value)
  105.                                      : AbstractContext
  106.                                      (out,
  107.                                       render_start_symbol,
  108.                                       render_stop_symbol,
  109.                                       render_null_value)
  110. {
  111.   if(this->render_start_symbol_)
  112.     this->out_ << "[";
  113. }
  114.  
  115. template<typename Ancestor>
  116. ArrayContext<Ancestor>::~ArrayContext()
  117. {
  118.   if(this->render_stop_symbol_)
  119.     this->out_ << "]";
  120. }
  121.  
  122. template<typename Ancestor>
  123. ArrayContext<Ancestor>& ArrayContext<Ancestor>::Number(int64_t value)
  124. {
  125.   this->WriteNumber(value);
  126.   return *this;
  127. }  
  128.  
  129. template<typename Ancestor>
  130. ArrayContext<Ancestor>& ArrayContext<Ancestor>::String(string_view value)
  131. {
  132.   this->WriteString(value);
  133.   return *this;
  134. }
  135.  
  136. template<typename Ancestor>
  137. ArrayContext<Ancestor>& ArrayContext<Ancestor>::Boolean(bool value)
  138. {
  139.   this->WriteBoolean(value);
  140.   return *this;
  141. }
  142.  
  143. template<typename Ancestor>
  144. ArrayContext<Ancestor>& ArrayContext<Ancestor>::Null()
  145. {
  146.   this->WriteNull();
  147.   return *this;
  148. }
  149.  
  150. void AbstractContext::WriteNumber(int64_t number)
  151. {
  152.   InsertDelimeter_();
  153.   out_ << number;
  154. }
  155.  
  156. void AbstractContext::WriteString(std::string_view str)
  157. {
  158.   InsertDelimeter_();
  159.   out_ << '"';
  160.   PrintJsonString(out_, str);
  161.   out_ << '"';
  162. }
  163.  
  164. void AbstractContext::WriteBoolean(bool value)
  165. {
  166.   InsertDelimeter_();
  167.   value ? out_ << "true" : out_ << "false";
  168. }
  169.  
  170. void AbstractContext::WriteNull()
  171. {
  172.   InsertDelimeter_();
  173.   out_ << "null";
  174. }
  175.  
  176. void AbstractContext::InsertDelimeter_()
  177. {
  178.   if(this->render_start_symbol_)
  179.   {
  180.     this->render_start_symbol_ = false;
  181.   }
  182.   else
  183.   {
  184.     this->out_ << ',';
  185.   }
  186. }
  187.  
  188. template <typename Ancestor>
  189. ArrayContext<ArrayContext<Ancestor>> ArrayContext<Ancestor>::BeginArray()
  190. {
  191.   InsertDelimeter_();
  192.   return ArrayContext<ArrayContext<Ancestor>>(out_);
  193. }
  194.  
  195. template <typename Ancestor>
  196. Ancestor ArrayContext<Ancestor>::EndArray()
  197. {
  198.   if(render_stop_symbol_)
  199.     out_ << ']';
  200.   render_stop_symbol_ = false;
  201.   return Ancestor(out_, false, false, false);
  202. }
  203.  
  204. template <typename Ancestor>
  205. ObjectKeyContext<ArrayContext<Ancestor>> ArrayContext<Ancestor>::BeginObject()
  206. {
  207.   InsertDelimeter_();
  208.   return ObjectKeyContext<ArrayContext<Ancestor>>(out_);
  209. }
  210.  
  211. template<typename Ancestor>
  212. class ObjectKeyContext : public AbstractContext
  213. {
  214.   public:
  215.     ObjectKeyContext(std::ostream &out,
  216.                      bool render_start_symbol = true,
  217.                      bool render_stop_symbol = true,
  218.                      bool render_null_value = true);
  219.     ~ObjectKeyContext();
  220.     Ancestor EndObject();
  221.     ObjectValueContext<Ancestor> Key(std::string_view key);
  222. };
  223.  
  224. ObjectKeyContext<NoneContext> PrintJsonObject(std::ostream &out)
  225. {
  226.   return ObjectKeyContext<NoneContext>(out);
  227. }
  228.  
  229. template<typename Ancestor>
  230. ObjectKeyContext<Ancestor>::ObjectKeyContext(std::ostream &out,
  231.                                              bool render_start_symbol,
  232.                                              bool render_stop_symbol,
  233.                                              bool render_null_value)
  234.                                              : AbstractContext
  235.                                              (out,
  236.                                               render_start_symbol,
  237.                                               render_stop_symbol,
  238.                                               render_null_value)
  239. {
  240.   if(this->render_start_symbol_)
  241.     this->out_ << "{";
  242. }
  243.  
  244. template<typename Ancestor>
  245. ObjectValueContext<Ancestor> ObjectKeyContext<Ancestor>::Key(std::string_view key)
  246. {
  247.   this->InsertDelimeter_();
  248.   this->out_ << '"';
  249.   PrintJsonString(this->out_, key);
  250.   this->out_ << '"';
  251.   return ObjectValueContext<Ancestor>(this->out_);
  252. }
  253.  
  254. template<typename Ancestor>
  255. ObjectKeyContext<Ancestor>::~ObjectKeyContext()
  256. {
  257.   if(!this->render_stop_symbol_ && this->render_null_value_)
  258.     this->out_ << "null}";
  259.   if(this->render_stop_symbol_)
  260.     this->out_ << "}";
  261. }
  262.  
  263. template <typename Ancestor>
  264. Ancestor ObjectKeyContext<Ancestor>::EndObject()
  265. {
  266.   this->render_stop_symbol_ = false;
  267.   this->render_null_value_ = false;
  268.   return Ancestor(out_, false, false, false);
  269. }
  270.  
  271. template<typename Ancestor>
  272. class ObjectValueContext : public AbstractContext
  273. {
  274.   public:
  275.     ObjectValueContext(std::ostream &out,
  276.                        bool render_start_symbol = true,
  277.                        bool render_stop_symbol = true,
  278.                        bool render_null_value = true);
  279.  
  280.     ~ObjectValueContext();
  281.     ObjectKeyContext<Ancestor> Number(int64_t);
  282.     ObjectKeyContext<Ancestor> String(std::string_view);
  283.     ObjectKeyContext<Ancestor> Boolean(bool);
  284.     ObjectKeyContext<Ancestor> Null();
  285.  
  286.     ArrayContext<ObjectKeyContext<Ancestor>> BeginArray();
  287.     ObjectKeyContext<ObjectKeyContext<Ancestor>> BeginObject();
  288.  
  289. };
  290.  
  291. template<typename Ancestor>
  292. ObjectValueContext<Ancestor>::ObjectValueContext(std::ostream &out,
  293.                                                  bool render_start_symbol,
  294.                                                  bool render_stop_symbol,
  295.                                                  bool render_null_value)
  296.                                                  : AbstractContext
  297.                                                  (out,
  298.                                                   render_start_symbol,
  299.                                                   render_stop_symbol,
  300.                                                   render_null_value)
  301. {
  302.   if(this->render_start_symbol_)
  303.     this->out_ << ":";
  304. }
  305.  
  306. template<typename Ancestor>
  307. ObjectValueContext<Ancestor>::~ObjectValueContext()
  308. {
  309. }
  310.  
  311. template<typename Ancestor>
  312. ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Number(int64_t value)
  313. {
  314.   this->WriteNumber(value);
  315.   return ObjectKeyContext<Ancestor>(this->out_, false, false, false);
  316. }
  317.  
  318. template<typename Ancestor>
  319. ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::String(string_view value)
  320. {
  321.   this->WriteString(value);
  322.   return ObjectKeyContext<Ancestor>(this->out_, false, false, false);
  323. }
  324.  
  325. template<typename Ancestor>
  326. ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Boolean(bool value)
  327. {
  328.   this->WriteBoolean(value);
  329.   return ObjectKeyContext<Ancestor>(this->out_, false, false, false);
  330. }
  331.  
  332. template<typename Ancestor>
  333. ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Null()
  334. {
  335.   this->WriteNull();
  336.   return ObjectKeyContext<Ancestor>(this->out_, false, false, false);
  337. }
  338.  
  339. template <typename Ancestor>
  340. ArrayContext<ObjectKeyContext<Ancestor>> ObjectValueContext<Ancestor>::BeginArray()
  341. {
  342.   InsertDelimeter_();
  343.   return ArrayContext<ObjectKeyContext<Ancestor>>(out_);
  344. }
  345.  
  346. template <typename Ancestor>
  347. ObjectKeyContext<ObjectKeyContext<Ancestor>> ObjectValueContext<Ancestor>::BeginObject()
  348. {
  349.   InsertDelimeter_();
  350.   return ObjectKeyContext<ObjectKeyContext<Ancestor>>(out_, true, false);
  351. }
  352.  
  353. //------------------------------------------- TESTING SECTION -------------------------------------------//
  354.  
  355. void TestPrintJsonString()
  356. {
  357.   std::ostringstream output;
  358.   PrintJsonString(output, "Hello, \"world\"");
  359.   ASSERT_EQUAL(output.str(), "Hello, \\\"world\\\"");
  360. }
  361.  
  362. void TestArray()
  363. {
  364.   std::ostringstream output;
  365.  
  366.   {
  367.     auto json = PrintJsonArray(output);
  368.     json
  369.         .Number(5)
  370.         .Number(6)
  371.         .BeginArray()
  372.           .Number(7)
  373.           .EndArray()
  374.         .Number(8)
  375.         .String("bingo!")
  376.         .EndArray();
  377.   }
  378.  
  379.   ASSERT_EQUAL(output.str(), R"([5,6,[7],8,"bingo!"])");
  380. }
  381.  
  382. void TestArrayWOEnd()
  383. {
  384.   std::ostringstream output;
  385.  
  386.   {
  387.     auto json = PrintJsonArray(output);
  388.     json
  389.         .Number(5)
  390.         .Number(6)
  391.         .BeginArray()
  392.           .Number(7);
  393.   }
  394.  
  395.   ASSERT_EQUAL(output.str(), R"([5,6,[7]])");
  396. }
  397.  
  398. void TestObject()
  399. {
  400.   std::ostringstream output;
  401.  
  402.   {
  403.     auto json = PrintJsonObject(output);
  404.     json
  405.         .Key("id1")
  406.         .Number(1234)
  407.         .Key("id2")
  408.         .Boolean(false)
  409.         .Key("")
  410.         .Null()
  411.         .Key("\"")
  412.         .String("\\");
  413.   }
  414.  
  415.   ASSERT_EQUAL(output.str(), R"({"id1":1234,"id2":false,"":null,"\"":"\\"})");
  416. }
  417.  
  418. void TestAutoClose()
  419. {
  420.  std::ostringstream output;
  421.  
  422.  {
  423.    auto json = PrintJsonArray(output);
  424.    json.BeginArray().BeginObject();
  425.  }
  426.  
  427.  ASSERT_EQUAL(output.str(), R"([[{}]])");
  428. }
  429.  
  430. void TetsEx1()
  431. {
  432.  std::ostringstream output;
  433.  {
  434.    auto json = PrintJsonArray(output);
  435.    json
  436.      .Null()
  437.      .String("Hello")
  438.      .Number(123)
  439.      .Boolean(false)
  440.      .EndArray();
  441.  }
  442.  ASSERT_EQUAL(output.str(), R"([null,"Hello",123,false])");
  443. }
  444.  
  445. void TetsEx2()
  446. {
  447.  std::ostringstream output;
  448.  {
  449.    auto json = PrintJsonArray(output);
  450.    json
  451.      .String("Hello")
  452.      .BeginArray()
  453.      .String("World");
  454.  }
  455.  ASSERT_EQUAL(output.str(), R"(["Hello",["World"]])");
  456. }
  457.  
  458. void TetsEx3()
  459. {
  460.  std::ostringstream output;
  461.  {
  462.    auto json = PrintJsonObject(output);
  463.    json
  464.      .Key("foo")
  465.      .BeginArray()
  466.      .String("Hello")
  467.      .EndArray()
  468.      .Key("foo")  // повторяющиеся ключи допускаются
  469.      .BeginObject()
  470.      .Key("foo");
  471.  }
  472.  ASSERT_EQUAL(output.str(), R"({"foo":["Hello"],"foo":{"foo":null}})");
  473. }
  474.  
  475. void TestEndObject_1()
  476. {
  477.  std::ostringstream output;
  478.  
  479.  {
  480.    auto json = PrintJsonArray(output);
  481.    json
  482.      .BeginObject()
  483.        .Key("as")
  484.        .Null()
  485.      .EndObject()
  486.      .BeginObject();
  487.  }
  488.  
  489.  ASSERT_EQUAL(output.str(), R"([{"as":null,{}}])");
  490. }
  491.  
  492. void TestEndObject_2()
  493. {
  494.  std::ostringstream output;
  495.  
  496.  {
  497.    auto json = PrintJsonArray(output);
  498.    json
  499.      .BeginObject()
  500.        .Key("as")
  501.        .BeginObject()
  502.        .EndObject()
  503.        .Key("as")
  504.        .Null()
  505.      .EndObject()
  506.      .BeginObject();
  507.  }
  508.  
  509.  ASSERT_EQUAL(output.str(), R"([{"as":null,{}}])");
  510. }
  511.  
  512. int main()
  513. {
  514.  TestRunner tr;
  515.  RUN_TEST(tr, TestPrintJsonString);
  516.  RUN_TEST(tr, TestArray);
  517.  RUN_TEST(tr, TestArrayWOEnd);
  518.  RUN_TEST(tr, TestObject);
  519.  RUN_TEST(tr, TestAutoClose);
  520.  RUN_TEST(tr, TetsEx1);
  521.  RUN_TEST(tr, TetsEx2);
  522.  RUN_TEST(tr, TetsEx3);
  523.  RUN_TEST(tr, TestEndObject_1);
  524.  
  525.  PrintJsonArray(std::cout)
  526.  .Null()
  527.  .String("Hello")
  528.  .Number(123)
  529.  .Boolean(false)
  530.  .BeginObject()
  531.    .Key("A")
  532.    .BeginArray()
  533.      .Null()
  534.      .String("Hello")
  535.      .Number(123)
  536.    .EndArray();
  537.  
  538.  return 0;
  539. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement