shushus

Спринт 12. Строим JSON. Задание 1.

Apr 16th, 2023
754
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 18.68 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. json.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <iostream>
  7. #include <map>
  8. #include <string>
  9. #include <variant>
  10. #include <vector>
  11.  
  12. namespace json {
  13.  
  14. class Node;
  15. using Dict = std::map<std::string, Node>;
  16. using Array = std::vector<Node>;
  17.  
  18. class ParsingError : public std::runtime_error {
  19. public:
  20.     using runtime_error::runtime_error;
  21. };
  22.  
  23. class Node final : private std::variant<std::nullptr_t, Array, Dict, bool, int, double, std::string> {
  24. public:
  25.     using variant::variant;
  26.     using Value = variant;
  27.  
  28.     bool IsInt() const {
  29.         return std::holds_alternative<int>(*this);
  30.     }
  31.    
  32.     int AsInt() const {
  33.         using namespace std::literals;
  34.         if (!IsInt()) {
  35.             throw std::logic_error("Not an int"s);
  36.         }
  37.         return std::get<int>(*this);
  38.     }
  39.  
  40.     bool IsPureDouble() const {
  41.         return std::holds_alternative<double>(*this);
  42.     }
  43.    
  44.     bool IsDouble() const {
  45.         return IsInt() || IsPureDouble();
  46.     }
  47.    
  48.     double AsDouble() const {
  49.         using namespace std::literals;
  50.        
  51.         if (!IsDouble()) {
  52.             throw std::logic_error("Not a double"s);
  53.         }
  54.         return IsPureDouble() ? std::get<double>(*this) : AsInt();
  55.     }
  56.  
  57.     bool IsBool() const {
  58.         return std::holds_alternative<bool>(*this);
  59.     }
  60.    
  61.     bool AsBool() const {
  62.         using namespace std::literals;
  63.        
  64.         if (!IsBool()) {
  65.             throw std::logic_error("Not a bool"s);
  66.         }
  67.  
  68.         return std::get<bool>(*this);
  69.     }
  70.  
  71.     bool IsNull() const {
  72.         return std::holds_alternative<std::nullptr_t>(*this);
  73.     }
  74.  
  75.     bool IsArray() const {
  76.         return std::holds_alternative<Array>(*this);
  77.     }
  78.        
  79.     const Array& AsArray() const {
  80.         using namespace std::literals;
  81.        
  82.         if (!IsArray()) {
  83.             throw std::logic_error("Not an array"s);
  84.         }
  85.  
  86.         return std::get<Array>(*this);
  87.     }
  88.  
  89.     bool IsString() const {
  90.         return std::holds_alternative<std::string>(*this);
  91.     }
  92.        
  93.     const std::string& AsString() const {
  94.         using namespace std::literals;
  95.        
  96.         if (!IsString()) {
  97.             throw std::logic_error("Not a string"s);
  98.         }
  99.  
  100.         return std::get<std::string>(*this);
  101.     }
  102.  
  103.     bool IsDict() const {
  104.         return std::holds_alternative<Dict>(*this);
  105.     }
  106.        
  107.     const Dict& AsDict() const {
  108.         using namespace std::literals;
  109.        
  110.         if (!IsDict()) {
  111.             throw std::logic_error("Not a dict"s);
  112.         }
  113.  
  114.         return std::get<Dict>(*this);
  115.     }
  116.  
  117.     bool operator==(const Node& rhs) const {
  118.         return GetValue() == rhs.GetValue();
  119.     }
  120.  
  121.     const Value& GetValue() const {
  122.         return *this;
  123.     }
  124. };
  125.  
  126. inline bool operator!=(const Node& lhs, const Node& rhs) {
  127.     return !(lhs == rhs);
  128. }
  129.  
  130. class Document {
  131. public:
  132.     explicit Document(Node root)
  133.         : root_(std::move(root)) {
  134.     }
  135.  
  136.     const Node& GetRoot() const {
  137.         return root_;
  138.     }
  139.  
  140. private:
  141.     Node root_;
  142. };
  143.  
  144. inline bool operator==(const Document& lhs, const Document& rhs) {
  145.     return lhs.GetRoot() == rhs.GetRoot();
  146. }
  147.  
  148. inline bool operator!=(const Document& lhs, const Document& rhs) {
  149.     return !(lhs == rhs);
  150. }
  151.  
  152. Document Load(std::istream& input);
  153.  
  154. void Print(const Document& doc, std::ostream& output);
  155.  
  156. }//end namespace json
  157. -----------------------------------------------------------------------
  158. json.cpp
  159. -----------------------------------------------------------------------
  160. #include "json.h"
  161.  
  162. #include <iterator>
  163.  
  164. namespace json {
  165.  
  166. namespace {
  167. using namespace std::literals;
  168.  
  169. Node LoadNode(std::istream& input);
  170. Node LoadString(std::istream& input);
  171.  
  172. std::string LoadLiteral(std::istream& input) {
  173.     std::string s;
  174.    
  175.     while (std::isalpha(input.peek())) {
  176.         s.push_back(static_cast<char>(input.get()));
  177.     }
  178.     return s;
  179. }
  180.  
  181. Node LoadArray(std::istream& input) {
  182.     std::vector<Node> result;
  183.  
  184.     for (char c; input >> c && c != ']';) {
  185.        
  186.         if (c != ',') {
  187.             input.putback(c);
  188.         }
  189.         result.push_back(LoadNode(input));
  190.     }
  191.    
  192.     if (!input) {
  193.         throw ParsingError("Array parsing error"s);
  194.     }
  195.    
  196.     return Node(std::move(result));
  197. }
  198.  
  199. Node LoadDict(std::istream& input) {
  200.     Dict dict;
  201.  
  202.     for (char c; input >> c && c != '}';) {
  203.        
  204.         if (c == '"') {
  205.             std::string key = LoadString(input).AsString();
  206.            
  207.             if (input >> c && c == ':') {
  208.                
  209.                 if (dict.find(key) != dict.end()) {
  210.                     throw ParsingError("Duplicate key '"s + key + "' have been found");
  211.                 }
  212.                
  213.                 dict.emplace(std::move(key), LoadNode(input));
  214.                
  215.             } else {
  216.                
  217.                 throw ParsingError(": is expected but '"s + c + "' has been found"s);
  218.             }
  219.            
  220.         } else if (c != ',') {
  221.             throw ParsingError(R"(',' is expected but ')"s + c + "' has been found"s);
  222.         }
  223.     }
  224.    
  225.     if (!input) {
  226.         throw ParsingError("Dictionary parsing error"s);
  227.     }
  228.    
  229.     return Node(std::move(dict));
  230. }
  231.  
  232. Node LoadString(std::istream& input) {
  233.     auto it = std::istreambuf_iterator<char>(input);
  234.     auto end = std::istreambuf_iterator<char>();
  235.     std::string s;
  236.    
  237.     while (true) {
  238.        
  239.         if (it == end) {
  240.             throw ParsingError("String parsing error");
  241.         }
  242.        
  243.         const char ch = *it;
  244.         if (ch == '"') {
  245.             ++it;
  246.             break;
  247.            
  248.         } else if (ch == '\\') {
  249.             ++it;
  250.            
  251.             if (it == end) {
  252.                 throw ParsingError("String parsing error");
  253.             }
  254.            
  255.             const char escaped_char = *(it);
  256.             switch (escaped_char) {
  257.                 case 'n':
  258.                     s.push_back('\n');
  259.                     break;
  260.                 case 't':
  261.                     s.push_back('\t');
  262.                     break;
  263.                 case 'r':
  264.                     s.push_back('\r');
  265.                     break;
  266.                 case '"':
  267.                     s.push_back('"');
  268.                     break;
  269.                 case '\\':
  270.                     s.push_back('\\');
  271.                     break;
  272.                 default:
  273.                     throw ParsingError("Unrecognized escape sequence \\"s + escaped_char);
  274.                    
  275.             }
  276.            
  277.         } else if (ch == '\n' || ch == '\r') {
  278.             throw ParsingError("Unexpected end of line"s);
  279.            
  280.         } else {
  281.             s.push_back(ch);
  282.            
  283.         }
  284.        
  285.         ++it;
  286.     }
  287.  
  288.     return Node(std::move(s));
  289. }
  290.  
  291. Node LoadBool(std::istream& input) {
  292.     const auto s = LoadLiteral(input);
  293.    
  294.     if (s == "true"sv) {
  295.         return Node{true};
  296.        
  297.     } else if (s == "false"sv) {
  298.         return Node{false};
  299.        
  300.     } else {
  301.         throw ParsingError("Failed to parse '"s + s + "' as bool"s);
  302.     }
  303. }
  304.  
  305. Node LoadNull(std::istream& input) {
  306.     if (auto literal = LoadLiteral(input); literal == "null"sv) {
  307.         return Node{nullptr};
  308.        
  309.     } else {
  310.         throw ParsingError("Failed to parse '"s + literal + "' as null"s);
  311.     }
  312. }
  313.  
  314. Node LoadNumber(std::istream& input) {
  315.     std::string parsed_num;
  316.  
  317.     auto read_char = [&parsed_num, &input] {
  318.         parsed_num += static_cast<char>(input.get());
  319.        
  320.         if (!input) {
  321.             throw ParsingError("Failed to read number from stream"s);
  322.         }
  323.     };
  324.  
  325.     auto read_digits = [&input, read_char] {
  326.         if (!std::isdigit(input.peek())) {
  327.             throw ParsingError("A digit is expected"s);
  328.         }
  329.        
  330.         while (std::isdigit(input.peek())) {
  331.             read_char();
  332.         }
  333.        
  334.     };
  335.  
  336.     if (input.peek() == '-') {
  337.         read_char();
  338.        
  339.     }
  340.  
  341.     if (input.peek() == '0') {
  342.         read_char();
  343.        
  344.     } else {
  345.         read_digits();
  346.        
  347.     }
  348.  
  349.     bool is_int = true;
  350.     if (input.peek() == '.') {
  351.         read_char();
  352.         read_digits();
  353.         is_int = false;
  354.        
  355.     }
  356.  
  357.     if (int ch = input.peek(); ch == 'e' || ch == 'E') {
  358.         read_char();
  359.        
  360.         if (ch = input.peek(); ch == '+' || ch == '-') {
  361.             read_char();
  362.         }
  363.        
  364.         read_digits();
  365.         is_int = false;
  366.     }
  367.  
  368.     try {
  369.        
  370.         if (is_int) {
  371.            
  372.             try {
  373.                 return std::stoi(parsed_num);
  374.             } catch (...) {
  375.  
  376.             }
  377.         }
  378.        
  379.         return std::stod(parsed_num);
  380.        
  381.     } catch (...) {
  382.         throw ParsingError("Failed to convert "s + parsed_num + " to number"s);
  383.     }
  384.    
  385. }
  386.  
  387. Node LoadNode(std::istream& input) {
  388.     char c;
  389.    
  390.     if (!(input >> c)) {
  391.         throw ParsingError("Unexpected EOF"s);
  392.     }
  393.    
  394.     switch (c) {
  395.         case '[':
  396.             return LoadArray(input);
  397.         case '{':
  398.             return LoadDict(input);
  399.         case '"':
  400.             return LoadString(input);
  401.         case 't':
  402.             [[fallthrough]];
  403.         case 'f':
  404.             input.putback(c);
  405.             return LoadBool(input);
  406.         case 'n':
  407.             input.putback(c);
  408.             return LoadNull(input);
  409.         default:
  410.             input.putback(c);
  411.             return LoadNumber(input);
  412.     }
  413. }
  414.  
  415. struct PrintContext {
  416.     std::ostream& out;
  417.     int indent_step = 4;
  418.     int indent = 0;
  419.  
  420.     void PrintIndent() const {
  421.         for (int i = 0; i < indent; ++i) {
  422.             out.put(' ');
  423.         }
  424.     }
  425.  
  426.     PrintContext Indented() const {
  427.         return {out,
  428.                 indent_step,
  429.                 indent_step + indent};
  430.     }
  431. };
  432.  
  433. void PrintNode(const Node& value, const PrintContext& ctx);
  434.  
  435. template <typename Value>
  436. void PrintValue(const Value& value, const PrintContext& ctx) {
  437.     ctx.out << value;
  438. }
  439.  
  440. void PrintString(const std::string& value, std::ostream& out) {
  441.     out.put('"');
  442.    
  443.     for (const char c : value) {
  444.         switch (c) {
  445.             case '\r':
  446.                 out << "\\r"sv;
  447.                 break;
  448.             case '\n':
  449.                 out << "\\n"sv;
  450.                 break;
  451.             case '"':
  452.                 [[fallthrough]];
  453.             case '\\':
  454.                 out.put('\\');
  455.                 [[fallthrough]];
  456.             default:
  457.                 out.put(c);
  458.                 break;
  459.         }
  460.     }
  461.    
  462.     out.put('"');
  463. }
  464.  
  465. template <>
  466. void PrintValue<std::string>(const std::string& value, const PrintContext& ctx) {
  467.     PrintString(value, ctx.out);
  468. }
  469.  
  470. template <>
  471. void PrintValue<std::nullptr_t>(const std::nullptr_t&, const PrintContext& ctx) {
  472.     ctx.out << "null"sv;
  473. }
  474.  
  475. template <>
  476. void PrintValue<bool>(const bool& value, const PrintContext& ctx) {
  477.     ctx.out << (value ? "true"sv : "false"sv);
  478. }
  479.  
  480. template <>
  481. void PrintValue<Array>(const Array& nodes, const PrintContext& ctx) {
  482.     std::ostream& out = ctx.out;
  483.     out << "[\n"sv;
  484.     bool first = true;
  485.    
  486.     auto inner_ctx = ctx.Indented();
  487.     for (const Node& node : nodes) {
  488.         if (first) {
  489.             first = false;
  490.            
  491.         } else {
  492.             out << ",\n"sv;
  493.            
  494.         }
  495.        
  496.         inner_ctx.PrintIndent();
  497.         PrintNode(node, inner_ctx);
  498.     }
  499.    
  500.     out.put('\n');
  501.     ctx.PrintIndent();
  502.     out.put(']');
  503. }
  504.  
  505. template <>
  506. void PrintValue<Dict>(const Dict& nodes, const PrintContext& ctx) {
  507.     std::ostream& out = ctx.out;
  508.     out << "{\n"sv;
  509.     bool first = true;
  510.    
  511.     auto inner_ctx = ctx.Indented();
  512.     for (const auto& [key, node] : nodes) {
  513.        
  514.         if (first) {
  515.             first = false;
  516.         } else {
  517.             out << ",\n"sv;
  518.         }
  519.        
  520.         inner_ctx.PrintIndent();
  521.         PrintString(key, ctx.out);
  522.         out << ": "sv;
  523.         PrintNode(node, inner_ctx);
  524.     }
  525.    
  526.     out.put('\n');
  527.     ctx.PrintIndent();
  528.     out.put('}');
  529. }
  530.  
  531. void PrintNode(const Node& node, const PrintContext& ctx) {
  532.     std::visit(
  533.         [&ctx](const auto& value) {PrintValue(value, ctx);},node.GetValue());
  534. }
  535.  
  536. }//end namespace
  537.  
  538. Document Load(std::istream& input) {
  539.     return Document{LoadNode(input)};
  540. }
  541.  
  542. void Print(const Document& doc, std::ostream& output) {
  543.     PrintNode(doc.GetRoot(), PrintContext{output});
  544. }
  545.  
  546. }//end namespace json
  547. -----------------------------------------------------------------------
  548. json_builder.h
  549. -----------------------------------------------------------------------
  550. #pragma once
  551.  
  552. #include "json.h"
  553. #include <stack>
  554. #include <string>
  555. #include <memory>
  556.  
  557. namespace json {
  558.    
  559. class Builder {
  560. public:
  561.    
  562.     Node make_node(Node::Value value_);
  563.     void add_node(Node node);
  564.    
  565.     Builder& Key(std::string key_);
  566.     Builder& Value(Node::Value value_);
  567.    
  568.     Builder& StartDict();
  569.     Builder& EndDict();
  570.    
  571.     Builder& StartArray();
  572.     Builder& EndArray();
  573.    
  574.     Node Build();
  575.    
  576. private:
  577.     Node root_;
  578.     std::vector<std::unique_ptr<Node>>nodes_stack_;
  579.    
  580. };
  581.    
  582. }//end namespace json
  583. -----------------------------------------------------------------------
  584. json_builder.cpp
  585. -----------------------------------------------------------------------
  586. #include "json_builder.h"
  587.  
  588. namespace json {
  589.  
  590. Node Builder::make_node(Node::Value value_) {
  591.     Node node;
  592.    
  593.     if (std::holds_alternative<bool>(value_)) {
  594.         bool bol = std::get<bool>(value_);
  595.         node = Node(bol);
  596.        
  597.     } else if (std::holds_alternative<int>(value_)) {
  598.         int intt = std::get<int>(value_);
  599.         node = Node(intt);
  600.        
  601.     } else if (std::holds_alternative<double>(value_)) {
  602.         double doble = std::get<double>(value_);
  603.         node = Node(doble);
  604.        
  605.     } else if (std::holds_alternative<std::string>(value_)) {
  606.         std::string str = std::get<std::string>(value_);
  607.         node = Node(std::move(str));
  608.        
  609.     } else if (std::holds_alternative<Array>(value_)) {
  610.         Array arr = std::get<Array>(value_);
  611.         node = Node(std::move(arr));
  612.        
  613.     } else if (std::holds_alternative<Dict>(value_)) {
  614.         Dict dictionary = std::get<Dict>(value_);
  615.         node = Node(std::move(dictionary));
  616.        
  617.     } else {
  618.         node = Node();
  619.     }
  620.    
  621.     return node;
  622. }
  623.  
  624. void Builder::add_node(Node node) {
  625.    
  626.     if (nodes_stack_.empty()) {
  627.        
  628.         if (!root_.IsNull()) {
  629.             throw std::logic_error("root has been added");
  630.         }        
  631.        
  632.         root_ = node;
  633.         return;
  634.        
  635.     } else {
  636.        
  637.         if (!nodes_stack_.back()->IsArray()
  638.             && !nodes_stack_.back()->IsString()) {
  639.            
  640.             throw std::logic_error("unable to create node");
  641.         }
  642.        
  643.         if (nodes_stack_.back()->IsArray()) {  
  644.             Array arr = nodes_stack_.back()->AsArray();
  645.             arr.emplace_back(node);
  646.            
  647.             nodes_stack_.pop_back();
  648.             auto arr_ptr = std::make_unique<Node>(arr);
  649.             nodes_stack_.emplace_back(std::move(arr_ptr));
  650.            
  651.             return;
  652.         }
  653.  
  654.         if (nodes_stack_.back()->IsString()) {
  655.             std::string str = nodes_stack_.back()->AsString();
  656.             nodes_stack_.pop_back();
  657.  
  658.             if (nodes_stack_.back()->IsDict()) {
  659.                 Dict dictionary = nodes_stack_.back()->AsDict();
  660.                 dictionary.emplace(std::move(str), node);
  661.                
  662.                 nodes_stack_.pop_back();
  663.                 auto dictionary_ptr = std::make_unique<Node>(dictionary);
  664.                 nodes_stack_.emplace_back(std::move(dictionary_ptr));
  665.             }
  666.            
  667.             return;
  668.         }
  669.     }    
  670. }
  671.    
  672. Builder& Builder::Key(std::string key_) {
  673.    
  674.     if (nodes_stack_.empty()) {
  675.         throw std::logic_error("unable to create key");
  676.     }
  677.    
  678.     auto key_ptr = std::make_unique<Node>(key_);
  679.    
  680.     if (nodes_stack_.back()->IsDict()) {
  681.         nodes_stack_.emplace_back(std::move(key_ptr));
  682.     }
  683.    
  684.     return *this;
  685. }
  686.    
  687. Builder& Builder::Value(Node::Value value_){
  688.     add_node(make_node(value_));
  689.     return *this;
  690. }
  691.    
  692. Builder& Builder::StartDict() {
  693.     nodes_stack_.emplace_back(std::move(std::make_unique<Node>(Dict())));
  694.     return *this;
  695. }
  696.    
  697. Builder& Builder::EndDict() {
  698.    
  699.     if (nodes_stack_.empty()) {
  700.         throw std::logic_error("unable to close as without opening");
  701.     }
  702.    
  703.     Node node = *nodes_stack_.back();
  704.    
  705.     if (!node.IsDict()) {
  706.         throw std::logic_error("object isn't dictionary");
  707.     }
  708.    
  709.     nodes_stack_.pop_back();
  710.     add_node(node);
  711.    
  712.     return *this;
  713. }
  714.    
  715. Builder& Builder::StartArray() {
  716.     nodes_stack_.emplace_back(std::move(std::make_unique<Node>(Array())));  
  717.     return *this;
  718. }
  719.    
  720. Builder& Builder::EndArray() {
  721.    
  722.     if (nodes_stack_.empty()) {
  723.         throw std::logic_error("unable to close without opening");
  724.     }
  725.    
  726.     Node node = *nodes_stack_.back();
  727.  
  728.     if (!node.IsArray()) {
  729.         throw std::logic_error("object isn't array");
  730.     }
  731.    
  732.     nodes_stack_.pop_back();
  733.     add_node(node);
  734.    
  735.     return *this;
  736. }
  737.    
  738. Node Builder::Build() {
  739.    
  740.     if (root_.IsNull()) {
  741.         throw std::logic_error("empty json");
  742.     }
  743.    
  744.     if (!nodes_stack_.empty()) {
  745.         throw std::logic_error("invalid json");
  746.     }    
  747.    
  748.     return root_;
  749. }
  750.    
  751. }//end namespace json
  752. -----------------------------------------------------------------------
  753. main.cpp
  754. -----------------------------------------------------------------------
  755. #include "json_builder.h"
  756.  
  757. #include <iostream>
  758.  
  759. using namespace std;
  760.  
  761. int main() {
  762.    
  763.     json::Print(
  764.         json::Document{
  765.             json::Builder{}
  766.             .StartDict()
  767.                 .Key("key1"s).Value(123)
  768.                 .Key("key2"s).Value("value2"s)
  769.                 .Key("key3"s).StartArray()
  770.                     .Value(456)
  771.                     .StartDict().EndDict()
  772.                     .StartDict()
  773.                         .Key(""s)
  774.                         .Value(nullptr)
  775.                     .EndDict()
  776.                     .Value(""s)
  777.                 .EndArray()
  778.             .EndDict()
  779.             .Build()
  780.         },
  781.         cout
  782.     );
  783.     cout << endl;
  784.  
  785.     json::Print(
  786.         json::Document{
  787.             json::Builder{}
  788.             .Value("just a string"s)
  789.             .Build()
  790.         },
  791.         cout
  792.     );
  793.     cout << endl;
  794.    
  795. }
Advertisement
Add Comment
Please, Sign In to add comment