Advertisement
azakharov93

full_json.cpp

Sep 19th, 2021
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.60 KB | None | 0 0
  1. #include "json.h"
  2.  
  3. #include <cctype>
  4. #include <cmath>
  5. #include <unordered_map>
  6.  
  7. using namespace std::string_literals;
  8.  
  9. namespace json {
  10.  
  11. namespace {
  12.  
  13. const std::unordered_map<char, char> kEscapeSymbolsDirectOrder{
  14.     {'\n', 'n'}, {'\t', 't'}, {'\r', 'r'}, {'\\', '\\'}, {'\"', '"'}};
  15.  
  16. const std::unordered_map<char, char> kEscapeSymbolsReversedOrder{
  17.     {'\\', '\\'}, {'"', '"'}, {'n', '\n'}, {'t', '\t'}, {'r', '\r'}};
  18.  
  19. struct NodeContainerPrinter {
  20.     std::ostream& out;
  21.  
  22.     void operator()(std::nullptr_t /* value */) const {
  23.         out << "null"s;
  24.     }
  25.     void operator()(bool value) const {
  26.         out << (value ? "true"s : "false"s);
  27.     }
  28.     void operator()(int value) const {
  29.         out << value;
  30.     }
  31.     void operator()(double value) const {
  32.         out << value;
  33.     }
  34.     void operator()(const std::string& value) const {
  35.         out << '"';
  36.  
  37.         for (const char symbol : value) {
  38.             if (kEscapeSymbolsDirectOrder.count(symbol) > 0) {
  39.                 out << '\\' << kEscapeSymbolsDirectOrder.at(symbol);
  40.             } else {
  41.                 out << symbol;
  42.             }
  43.         }
  44.  
  45.         out << '"';
  46.     }
  47.     void operator()(const Dict& map) const {
  48.         out << '{';
  49.         int id{0};
  50.         for (const auto& [key, value] : map) {
  51.             if (id++ != 0)
  52.                 out << ", "s;
  53.             out << '"' << key << '"';
  54.             out << ':';
  55.             std::visit(NodeContainerPrinter{out}, value.AsPureNodeContainer());
  56.         }
  57.         out << '}';
  58.     }
  59.     void operator()(const Array& array) const {
  60.         out << '[';
  61.  
  62.         int id{0};
  63.         for (const auto& value : array) {
  64.             if (id++ != 0)
  65.                 out << ", "s;
  66.             std::visit(NodeContainerPrinter{out}, value.AsPureNodeContainer());
  67.         }
  68.  
  69.         out << ']';
  70.     }
  71. };
  72.  
  73. /* Load methods */
  74.  
  75. std::string LoadLetters(std::istream& input) {
  76.     std::string result;
  77.     while (std::isalpha(input.peek()))
  78.         result.push_back(static_cast<char>(input.get()));
  79.  
  80.     return result;
  81. }
  82.  
  83. Node LoadNode(std::istream& input);
  84.  
  85. Node LoadNull(std::istream& input) {
  86.     if (auto value = LoadLetters(input); value == "null"s)
  87.         return Node{nullptr};
  88.  
  89.     throw ParsingError(R"(Incorrect format for Null Node parsing. "null" expected)"s);
  90. }
  91.  
  92. Node LoadBool(std::istream& input) {
  93.     std::string value = LoadLetters(input);
  94.     if (value == "true"s)
  95.         return Node{true};
  96.     if (value == "false"s)
  97.         return Node{false};
  98.  
  99.     throw ParsingError(R"(Incorrect format for Boolean Node parsing. "true" or "false" expected)"s);
  100. }
  101.  
  102. Node LoadArray(std::istream& input) {
  103.     Array result;
  104.  
  105.     for (char symbol; input >> symbol && symbol != ']';) {
  106.         if (symbol != ',')
  107.             input.putback(symbol);
  108.  
  109.         result.emplace_back(LoadNode(input));
  110.  
  111.         if (input >> symbol) {
  112.             // Break if this is the end of array
  113.             if (symbol == ']')
  114.                 break;
  115.             // If parsed element was not last, but there is no "," afterwards
  116.             if (symbol != ',')
  117.                 throw ParsingError(R"(All elements of the Array should be separated with the "," symbol)"s);
  118.         } else {
  119.             throw ParsingError(R"(During Array Node parsing expected "," or "]" symbols)"s);
  120.         }
  121.     }
  122.  
  123.     if (!input)
  124.         throw ParsingError("Incorrect format for Array Node parsing"s);
  125.  
  126.     return Node{std::move(result)};
  127. }
  128.  
  129. Node LoadNumber(std::istream& input) {
  130.     std::string parsed_num;
  131.  
  132.     // Считывает в parsed_num очередной символ из input
  133.     auto read_char = [&parsed_num, &input] {
  134.         parsed_num += static_cast<char>(input.get());
  135.         if (!input) {
  136.             throw ParsingError("Failed to read number from stream"s);
  137.         }
  138.     };
  139.  
  140.     // Считывает одну или более цифр в parsed_num из input
  141.     auto read_digits = [&input, read_char] {
  142.         if (!std::isdigit(input.peek())) {
  143.             throw ParsingError("A digit is expected"s);
  144.         }
  145.         while (std::isdigit(input.peek())) {
  146.             read_char();
  147.         }
  148.     };
  149.  
  150.     if (input.peek() == '-') {
  151.         read_char();
  152.     }
  153.     // Парсим целую часть числа
  154.     if (input.peek() == '0') {
  155.         read_char();
  156.         // После 0 в JSON не могут идти другие цифры
  157.     } else {
  158.         read_digits();
  159.     }
  160.  
  161.     bool is_int = true;
  162.     // Парсим дробную часть числа
  163.     if (input.peek() == '.') {
  164.         read_char();
  165.         read_digits();
  166.         is_int = false;
  167.     }
  168.  
  169.     // Парсим экспоненциальную часть числа
  170.     if (int ch = input.peek(); ch == 'e' || ch == 'E') {
  171.         read_char();
  172.         if (ch = input.peek(); ch == '+' || ch == '-') {
  173.             read_char();
  174.         }
  175.         read_digits();
  176.         is_int = false;
  177.     }
  178.  
  179.     try {
  180.         if (is_int) {
  181.             // Сначала пробуем преобразовать строку в int
  182.             try {
  183.                 return Node{std::stoi(parsed_num)};
  184.             } catch (...) {
  185.                 // В случае неудачи, например, при переполнении,
  186.                 // код ниже попробует преобразовать строку в double
  187.             }
  188.         }
  189.         return Node{std::stod(parsed_num)};
  190.     } catch (...) {
  191.         throw ParsingError("Failed to convert "s + parsed_num + " to number"s);
  192.     }
  193. }
  194.  
  195. Node LoadString(std::istream& input) {
  196.     if (!input)
  197.         throw ParsingError("Incorrect format for String Node parsing. Unexpected EOF"s);
  198.  
  199.     input >> std::noskipws;
  200.     std::string result;
  201.  
  202.     char current;
  203.     char escape_symbol;
  204.  
  205.     while (input >> current) {
  206.         // If " is not a part of \" symbol - this is the end of the line
  207.         if (current == '"')
  208.             break;
  209.  
  210.         // If string starts with '\\' -> this is an escape symbol
  211.         if (current == '\\') {
  212.             // If it is possible to read escape symbol (// is not the end of the string)
  213.             if (input >> escape_symbol) {
  214.                 if (kEscapeSymbolsReversedOrder.count(escape_symbol) > 0) {
  215.                     result += kEscapeSymbolsReversedOrder.at(escape_symbol);
  216.                 } else {
  217.                     throw ParsingError("Unknown escape symbol: \\"s + std::string{escape_symbol});
  218.                 }
  219.             } else {
  220.                 throw ParsingError("Incorrect input String for parsing"s);
  221.             }
  222.         } else {
  223.             result += current;
  224.         }
  225.     }
  226.  
  227.     input >> std::skipws;
  228.  
  229.     if (!input)
  230.         throw ParsingError("Incorrect input String for parsing"s);
  231.  
  232.     return Node{std::move(result)};
  233. }
  234.  
  235. Node LoadDict(std::istream& input) {
  236.     Dict result;
  237.  
  238.     for (char symbol; input >> symbol && symbol != '}';) {
  239.         if (symbol == '"') {
  240.             std::string key = LoadString(input).AsString();
  241.             if (result.count(key) > 0)
  242.                 throw ParsingError("Key "s + key + " is already exists in the Dict"s);
  243.  
  244.             if (input >> symbol && symbol != ':')
  245.                 throw ParsingError(R"(Dict "key" should be separated from "value" with ":" symbol)"s);
  246.  
  247.             result.emplace(std::move(key), LoadNode(input));
  248.         } else if (symbol != ',') {
  249.             throw ParsingError(R"(Dict {"key":value} pairs should be separated with "," symbol)"s);
  250.         }
  251.     }
  252.  
  253.     if (!input)
  254.         throw ParsingError("Incorrect format for Dict Node parsing"s);
  255.  
  256.     return Node{std::move(result)};
  257. }
  258.  
  259. Node LoadNode(std::istream& input) {
  260.     char symbol;
  261.     if (!(input >> symbol))
  262.         throw ParsingError("Incorrect format for Node parsing. Unexpected EOF"s);
  263.  
  264.     if (symbol == 'n') {
  265.         input.putback(symbol);
  266.         return LoadNull(input);
  267.     } else if (symbol == 't' || symbol == 'f') {
  268.         input.putback(symbol);
  269.         return LoadBool(input);
  270.     } else if (symbol == '[') {
  271.         return LoadArray(input);
  272.     } else if (symbol == '{') {
  273.         return LoadDict(input);
  274.     } else if (symbol == '"') {
  275.         return LoadString(input);
  276.     } else {
  277.         input.putback(symbol);
  278.         return LoadNumber(input);
  279.     }
  280. }
  281.  
  282. }  // namespace
  283.  
  284. /* Constructors */
  285.  
  286. Node::Node(bool value) : data_(value) {}
  287. Node::Node(std::nullptr_t /* value*/) : Node() {}
  288. Node::Node(int value) : data_(value) {}
  289. Node::Node(double value) : data_(value) {}
  290. Node::Node(std::string value) : data_(std::move(value)) {}
  291. Node::Node(Dict map) : data_(std::move(map)) {}
  292. Node::Node(Array array) : data_(std::move(array)) {}
  293.  
  294. /* Is-like methods */
  295.  
  296. bool Node::IsNull() const {
  297.     return std::holds_alternative<std::nullptr_t>(data_);
  298. }
  299. bool Node::IsBool() const {
  300.     return std::holds_alternative<bool>(data_);
  301. }
  302. bool Node::IsInt() const {
  303.     return std::holds_alternative<int>(data_);
  304. }
  305. bool Node::IsDouble() const {
  306.     return std::holds_alternative<double>(data_) || std::holds_alternative<int>(data_);
  307. }
  308. bool Node::IsPureDouble() const {
  309.     double integral_part{0.};
  310.     return !std::holds_alternative<int>(data_) && std::fmod(std::get<double>(data_), integral_part) != 0.;
  311. }
  312. bool Node::IsString() const {
  313.     return std::holds_alternative<std::string>(data_);
  314. }
  315. bool Node::IsArray() const {
  316.     return std::holds_alternative<Array>(data_);
  317. }
  318. bool Node::IsMap() const {
  319.     return std::holds_alternative<Dict>(data_);
  320. }
  321.  
  322. /* As-like methods */
  323.  
  324. const NodeContainer& Node::AsPureNodeContainer() const {
  325.     return data_;
  326. }
  327.  
  328. bool Node::AsBool() const {
  329.     if (auto* value = std::get_if<bool>(&data_))
  330.         return *value;
  331.     throw std::logic_error("Impossible to parse node as Boolean"s);
  332. }
  333.  
  334. int Node::AsInt() const {
  335.     if (auto* value = std::get_if<int>(&data_))
  336.         return *value;
  337.     throw std::logic_error("Impossible to parse node as Int "s);
  338. }
  339.  
  340. double Node::AsDouble() const {
  341.     if (auto* value = std::get_if<double>(&data_))
  342.         return *value;
  343.  
  344.     if (auto* value = std::get_if<int>(&data_))
  345.         return static_cast<double>(*value);
  346.  
  347.     throw std::logic_error("Impossible to parse node as Double "s);
  348. }
  349.  
  350. const std::string& Node::AsString() const {
  351.     if (auto* value = std::get_if<std::string>(&data_))
  352.         return *value;
  353.     throw std::logic_error("Impossible to parse node as String"s);
  354. }
  355.  
  356. const Array& Node::AsArray() const {
  357.     if (auto* value = std::get_if<Array>(&data_))
  358.         return *value;
  359.     throw std::logic_error("Impossible to parse node as Array"s);
  360. }
  361.  
  362. const Dict& Node::AsMap() const {
  363.     if (auto* value = std::get_if<Dict>(&data_))
  364.         return *value;
  365.     throw std::logic_error("Impossible to parse node as Dict"s);
  366. }
  367.  
  368. /* Operators */
  369.  
  370. bool operator==(const Node& left, const Node& right) {
  371.     return left.data_ == right.data_;
  372. }
  373.  
  374. bool operator!=(const Node& left, const Node& right) {
  375.     return !(left == right);
  376. }
  377.  
  378. /* Document */
  379.  
  380. Document::Document(Node root) : root_(std::move(root)) {}
  381.  
  382. const Node& Document::GetRoot() const {
  383.     return root_;
  384. }
  385.  
  386. bool operator==(const Document& left, const Document& right) {
  387.     return left.GetRoot() == right.GetRoot();
  388. }
  389.  
  390. bool operator!=(const Document& left, const Document& right) {
  391.     return !(left == right);
  392. }
  393.  
  394. Document Load(std::istream& input) {
  395.     return Document{LoadNode(input)};
  396. }
  397.  
  398. void Print(const Document& doc, std::ostream& output) {
  399.     std::visit(NodeContainerPrinter{output}, doc.GetRoot().AsPureNodeContainer());
  400.  
  401.     // Реализуйте функцию самостоятельно
  402. }
  403.  
  404. }  // namespace json
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement