LCOV - code coverage report
Current view: top level - src - reference.cpp (source / functions) Coverage Total Hit
Test: JSON Expression Parser Lines: 89.3 % 252 225
Test Date: 2024-11-04 20:34:32 Functions: 96.3 % 27 26
Branches: 59.6 % 356 212

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * The MIT License (MIT)
       3                 :             :  *
       4                 :             :  * Copyright (c) 2024 Yaroslav Riabtsev <yaroslav.riabtsev@rwth-aachen.de>
       5                 :             :  *
       6                 :             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       7                 :             :  * of this software and associated documentation files (the "Software"), to deal
       8                 :             :  * in the Software without restriction, including without limitation the rights
       9                 :             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      10                 :             :  * copies of the Software, and to permit persons to whom the Software is
      11                 :             :  * furnished to do so, subject to the following conditions:
      12                 :             :  *
      13                 :             :  * The above copyright notice and this permission notice shall be included
      14                 :             :  * in all copies or substantial portions of the Software.
      15                 :             :  *
      16                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17                 :             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18                 :             :  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
      19                 :             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20                 :             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      21                 :             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      22                 :             :  * SOFTWARE.
      23                 :             :  */
      24                 :             : 
      25                 :             : #include "reference.hpp"
      26                 :             : 
      27                 :             : #include <ranges>
      28                 :             : 
      29                 :          96 : reference_lib::json_reference::json_reference(const ref_head_type type)
      30         [ +  - ]:          96 :     : head_type(type) { }
      31                 :             : 
      32                 :         182 : reference_lib::json_reference::json_reference(const std::shared_ptr<json>& head)
      33                 :         182 :     : head_type(ref_head_type::object)
      34         [ +  - ]:         182 :     , head(head) { }
      35                 :             : 
      36                 :           8 : reference_lib::json_set::json_set(
      37                 :             :     const std::vector<std::shared_ptr<json_reference>>& elements
      38                 :           8 : )
      39         [ +  - ]:           8 :     : elements(elements) {
      40                 :           8 :     _reference_type = json_reference_type::set_json;
      41                 :           8 :     set_head_type(ref_head_type::accessor);
      42                 :           8 : }
      43                 :             : 
      44                 :          12 : reference_lib::json_function::json_function(std::string name)
      45                 :          12 :     : name(std::move(name)) {
      46                 :          12 :     _reference_type = json_reference_type::function_json;
      47                 :          12 : }
      48                 :             : 
      49                 :         179 : json_lib::json_type reference_lib::json_reference::type() const {
      50                 :         179 :     return json_lib::json_type::reference_json;
      51                 :             : }
      52                 :             : 
      53                 :          68 : std::string reference_lib::json_reference::indented_string(
      54                 :             :     const size_t indent_level, const bool pretty
      55                 :             : ) const {
      56                 :          68 :     std::string result;
      57   [ +  +  +  + ]:          68 :     switch (head_type) {
      58                 :          29 :     case ref_head_type::object:
      59   [ +  -  +  - ]:          29 :         result += head->indented_string(indent_level, pretty);
      60                 :          29 :         break;
      61                 :           1 :     case ref_head_type::local:
      62         [ +  - ]:           1 :         result += "@";
      63                 :           1 :         break;
      64                 :          28 :     case ref_head_type::root:
      65         [ +  - ]:          28 :         result += "$";
      66                 :          28 :         break;
      67                 :          68 :     default:;
      68                 :             :         // result += "+";
      69                 :             :     }
      70   [ +  -  +  - ]:          68 :     result += tail_to_string();
      71                 :          68 :     return result;
      72                 :           0 : }
      73                 :             : 
      74                 :           8 : std::string reference_lib::json_set::indented_string(size_t, bool) const {
      75                 :           8 :     std::string result;
      76         [ +  + ]:          39 :     for (const auto& element : elements) {
      77         [ +  + ]:          31 :         if (!result.empty()) {
      78         [ +  - ]:          23 :             result += ", ";
      79                 :             :         }
      80   [ +  -  +  - ]:          31 :         result += element->to_string();
      81                 :             :     }
      82         [ +  + ]:           8 :     if (get_head_type() == ref_head_type::set) {
      83   [ +  -  +  - ]:           6 :         result = '[' + result + ']';
      84                 :             :     } else {
      85   [ +  -  +  - ]:           2 :         result = '{' + result + '}';
      86                 :             :     }
      87   [ +  -  +  - ]:           8 :     result += tail_to_string();
      88                 :           8 :     return result;
      89                 :           0 : }
      90                 :             : 
      91                 :           9 : std::string reference_lib::json_function::indented_string(size_t, bool) const {
      92                 :           9 :     std::string result;
      93         [ +  + ]:          25 :     for (const auto& arg : args) {
      94         [ +  + ]:          16 :         if (!result.empty()) {
      95         [ +  - ]:           8 :             result += ", ";
      96                 :             :         }
      97   [ +  -  +  - ]:          16 :         result += arg->to_string();
      98                 :             :     }
      99   [ +  -  +  -  :           9 :     result = name + '(' + result + ')';
                   +  - ]
     100   [ +  -  +  - ]:           9 :     result += tail_to_string();
     101                 :           9 :     return result;
     102                 :           0 : }
     103                 :             : 
     104                 :          85 : std::string reference_lib::json_reference::tail_to_string() const {
     105                 :          85 :     std::string result;
     106         [ +  + ]:         154 :     for (const auto& accessor : tail) {
     107         [ +  - ]:          69 :         std::string suffix = accessor->to_string();
     108   [ +  -  +  + ]:          69 :         if (accessor->type() == json_lib::json_type::reference_json) {
     109         [ +  + ]:          20 :             if (std::dynamic_pointer_cast<json_reference>(accessor)
     110         [ +  - ]:          10 :                     ->reference_type()
     111                 :          10 :                 == json_reference_type::set_json) {
     112         [ +  - ]:           2 :                 result += suffix;
     113                 :           2 :                 continue;
     114                 :             :             }
     115                 :             :         }
     116   [ +  -  +  -  :          67 :         result += "[" + suffix + ']';
                   +  - ]
     117         [ +  + ]:          69 :     }
     118                 :          85 :     return result;
     119                 :           0 : }
     120                 :             : 
     121                 :           8 : void reference_lib::json_reference::touch() {
     122         [ -  + ]:           8 :     if (head_type == ref_head_type::object) {
     123                 :           0 :         head->touch();
     124                 :             :     }
     125         [ +  + ]:          11 :     for (const auto& accessor : tail) {
     126         [ +  - ]:           3 :         accessor->touch();
     127                 :             :     }
     128                 :           8 : }
     129                 :             : 
     130                 :           0 : void reference_lib::json_set::touch() {
     131         [ #  # ]:           0 :     for (const auto& element : elements) {
     132         [ #  # ]:           0 :         element->touch();
     133                 :             :     }
     134                 :           0 : }
     135                 :             : 
     136                 :          19 : void reference_lib::json_reference::set_root(const std::shared_ptr<json>& item
     137                 :             : ) {
     138         [ +  + ]:          68 :     for (const auto& accessor : tail) {
     139         [ +  - ]:          49 :         accessor->set_root(item);
     140                 :             :     }
     141         [ +  + ]:          19 :     if (head_type == ref_head_type::root) {
     142                 :          12 :         head = item;
     143                 :          12 :         head_type = ref_head_type::object;
     144                 :          12 :         simplify();
     145                 :             :     }
     146                 :          19 : }
     147                 :             : 
     148                 :           2 : void reference_lib::json_set::set_root(const std::shared_ptr<json>& item) {
     149         [ +  + ]:           8 :     for (const auto& element : elements) {
     150         [ +  - ]:           6 :         element->set_root(item);
     151                 :             :     }
     152                 :           2 : }
     153                 :             : 
     154                 :           4 : void reference_lib::json_function::set_root(const std::shared_ptr<json>& item) {
     155         [ +  + ]:           9 :     for (const auto& arg : args) {
     156         [ +  - ]:           5 :         arg->set_root(item);
     157                 :             :     }
     158                 :           4 : }
     159                 :             : 
     160                 :             : reference_lib::json_reference_type
     161                 :          30 : reference_lib::json_reference::reference_type() const {
     162                 :          30 :     return _reference_type;
     163                 :             : }
     164                 :             : 
     165                 :         166 : void reference_lib::json_reference::emplace_back(
     166                 :             :     const std::shared_ptr<json>& accessor
     167                 :             : ) {
     168   [ +  +  -  + ]:         166 :     const bool abstract = head_type != ref_head_type::object || length() > 0;
     169                 :         166 :     tail.emplace_back(accessor);
     170         [ +  + ]:         166 :     if (!abstract) {
     171                 :          47 :         simplify();
     172                 :             :     }
     173                 :         160 : }
     174                 :             : 
     175                 :           5 : void reference_lib::json_set::emplace_back(const std::shared_ptr<json>& item) {
     176         [ +  + ]:          23 :     for (const auto& element : elements) {
     177         [ +  - ]:          18 :         element->emplace_back(item);
     178                 :             :     }
     179                 :           5 : }
     180                 :             : 
     181                 :          12 : void reference_lib::json_function::set_args(
     182                 :             :     const std::vector<std::shared_ptr<json>>& args
     183                 :             : ) {
     184         [ +  + ]:          35 :     for (const auto& arg : args) {
     185   [ +  -  +  + ]:          23 :         if (arg->type() == json_lib::json_type::reference_json) {
     186                 :           7 :             if (const auto ref_arg
     187                 :           7 :                 = std::dynamic_pointer_cast<json_reference>(arg);
     188         [ +  - ]:           7 :                 ref_arg->length() == 0
     189   [ +  +  -  +  :           7 :                 && ref_arg->get_head_type() == ref_head_type::local) {
                   -  + ]
     190         [ #  # ]:           0 :                 throw std::invalid_argument("recursive function");
     191                 :           7 :             }
     192                 :             :         }
     193                 :             :     }
     194                 :          12 :     this->args = args;
     195                 :          12 : }
     196                 :             : 
     197                 :          20 : std::shared_ptr<json_lib::json> reference_lib::json_function::value() {
     198         [ +  + ]:          20 :     if (name == "size") {
     199         [ +  + ]:           8 :         if (args.size() != 1) {
     200         [ +  - ]:           1 :             return std::make_shared<json_lib::json_integer>(args.size());
     201                 :             :         }
     202         [ +  + ]:           7 :         if (args[0]->type() == json_lib::json_type::reference_json) {
     203                 :           6 :             args[0]
     204         [ +  - ]:          12 :                 = std::dynamic_pointer_cast<json_reference>(args[0])->value();
     205                 :             :         }
     206         [ +  + ]:           7 :         if (args[0]->type() == json_lib::json_type::array_json) {
     207                 :           2 :             return std::make_shared<json_lib::json_integer>(
     208   [ +  -  +  - ]:           4 :                 std::dynamic_pointer_cast<json_lib::json_array>(args[0])->size()
     209                 :           2 :             );
     210                 :             :         }
     211         [ +  + ]:           5 :         if (args[0]->type() == json_lib::json_type::object_json) {
     212                 :           1 :             return std::make_shared<json_lib::json_integer>(
     213   [ +  -  +  - ]:           2 :                 std::dynamic_pointer_cast<json_lib::json_object>(args[0])->size(
     214                 :             :                 )
     215                 :           1 :             );
     216                 :             :         }
     217   [ +  +  +  +  :          12 :     } else if (name == "min" || name == "max") {
                   +  + ]
     218         [ -  + ]:           7 :         if (args.empty()) {
     219                 :             :             throw std::invalid_argument(
     220         [ #  # ]:           0 :                 "trying to calculate `" + name + "()` of empty array"
     221   [ #  #  #  # ]:           0 :             );
     222                 :             :         }
     223         [ +  - ]:           7 :         const bool is_max = (name == "max");
     224                 :           7 :         int result = -1;
     225         [ +  + ]:           7 :         if (args.size() == 1) {
     226   [ +  -  +  - ]:           3 :             if (args[0]->type() == json_lib::json_type::reference_json) {
     227                 :           3 :                 args[0]
     228         [ +  - ]:           6 :                     = std::dynamic_pointer_cast<json_reference>(args[0])->value(
     229                 :           3 :                     );
     230                 :             :             }
     231   [ +  -  +  + ]:           3 :             if (args[0]->type() == json_lib::json_type::reference_json) {
     232         [ +  - ]:           2 :                 return shared_from_this();
     233                 :             :             }
     234   [ +  -  +  - ]:           1 :             if (args[0]->type() == json_lib::json_type::array_json) {
     235                 :             :                 const auto arr
     236                 :           1 :                     = std::dynamic_pointer_cast<json_lib::json_array>(args[0]);
     237         [ +  - ]:           1 :                 const int sz = static_cast<int>(arr->size());
     238         [ -  + ]:           1 :                 if (sz == 0) {
     239                 :             :                     throw std::invalid_argument(
     240         [ #  # ]:           0 :                         "trying to calculate `" + name + "()` of empty array"
     241   [ #  #  #  # ]:           0 :                     );
     242                 :             :                 }
     243         [ +  + ]:           3 :                 for (int i = 0; i < sz; ++i) {
     244         [ +  - ]:           2 :                     auto item = arr->at(i);
     245   [ +  -  -  + ]:           2 :                     if (item->type() == json_lib::json_type::reference_json) {
     246                 :           0 :                         item = std::dynamic_pointer_cast<json_reference>(item)
     247         [ #  # ]:           0 :                                    ->value();
     248                 :             :                     }
     249   [ +  -  -  + ]:           2 :                     if (item->type() == json_lib::json_type::reference_json) {
     250         [ #  # ]:           0 :                         return shared_from_this();
     251                 :             :                     }
     252   [ +  -  -  + ]:           2 :                     if (item->type() != json_lib::json_type::integer_json) {
     253                 :             :                         throw std::invalid_argument(
     254                 :           0 :                             "trying to calculate `" + name
     255         [ #  # ]:           0 :                             + "()` of not integer"
     256   [ #  #  #  # ]:           0 :                         );
     257                 :             :                     }
     258                 :             :                     const int val
     259                 :           2 :                         = std::dynamic_pointer_cast<json_lib::json_integer>(item
     260                 :             :                         )
     261         [ +  - ]:           2 :                               ->as_index();
     262   [ +  +  -  +  :           2 :                     if (i == 0 || (is_max && val > result)
                   -  - ]
     263   [ +  -  -  + ]:           1 :                         || (!is_max && val < result)) {
     264                 :           1 :                         result = val;
     265                 :             :                     }
     266         [ +  - ]:           2 :                 }
     267         [ +  - ]:           1 :             }
     268                 :             :         } else {
     269         [ +  + ]:           8 :             for (size_t i = 0; i < args.size(); ++i) {
     270                 :           6 :                 auto item = args[i];
     271   [ +  -  +  + ]:           6 :                 if (item->type() == json_lib::json_type::reference_json) {
     272                 :           8 :                     item = std::dynamic_pointer_cast<json_reference>(item)
     273         [ +  - ]:           8 :                                ->value();
     274                 :             :                 }
     275   [ +  -  +  + ]:           6 :                 if (item->type() == json_lib::json_type::reference_json) {
     276         [ +  - ]:           2 :                     return shared_from_this();
     277                 :             :                 }
     278   [ +  -  -  + ]:           4 :                 if (item->type() != json_lib::json_type::integer_json) {
     279                 :             :                     throw std::invalid_argument(
     280         [ #  # ]:           0 :                         "trying to calculate `" + name + "()` of not integer"
     281   [ #  #  #  # ]:           0 :                     );
     282                 :             :                 }
     283                 :             :                 const int val
     284                 :           4 :                     = std::dynamic_pointer_cast<json_lib::json_integer>(item)
     285         [ +  - ]:           4 :                           ->as_index();
     286   [ +  +  +  -  :           4 :                 if (i == 0 || (is_max && val > result)
                   -  + ]
     287   [ #  #  #  # ]:           0 :                     || (!is_max && val < result)) {
     288                 :           4 :                     result = val;
     289                 :             :                 }
     290         [ +  + ]:           6 :             }
     291                 :             :         }
     292         [ +  - ]:           3 :         return std::make_shared<json_lib::json_integer>(result);
     293                 :             :     }
     294                 :           9 :     return shared_from_this();
     295                 :             : }
     296                 :             : 
     297                 :          40 : void reference_lib::json_reference::set_parent(
     298                 :             :     const std::shared_ptr<json>& local
     299                 :             : ) {
     300         [ +  + ]:          40 :     if (head_type == ref_head_type::local
     301         [ +  + ]:          31 :         || head_type == ref_head_type::accessor) {
     302                 :             :         // todo: update_head(local);
     303                 :          30 :         head = local;
     304                 :          30 :         head_type = ref_head_type::object;
     305                 :          30 :         simplify();
     306                 :             :     }
     307                 :          40 : }
     308                 :             : 
     309                 :           6 : void reference_lib::json_set::set_parent(const std::shared_ptr<json>& local) {
     310         [ +  + ]:          27 :     for (const auto& element : elements) {
     311         [ +  - ]:          21 :         element->set_parent(local);
     312                 :             :     }
     313                 :           6 :     set_head_type(ref_head_type::set);
     314                 :           6 : }
     315                 :             : 
     316                 :           4 : void reference_lib::json_function::set_parent(const std::shared_ptr<json>& local
     317                 :             : ) {
     318         [ +  + ]:           9 :     for (auto& arg : args) {
     319   [ +  -  +  - ]:           5 :         if (arg->type() == json_lib::json_type::reference_json) {
     320                 :           5 :             const auto ref_arg = std::dynamic_pointer_cast<json_reference>(arg);
     321         [ +  - ]:           5 :             ref_arg->set_parent(local);
     322         [ +  - ]:           5 :             arg = ref_arg->value();
     323                 :           5 :         }
     324                 :             :     }
     325                 :           4 : }
     326                 :             : 
     327                 :         537 : size_t reference_lib::json_reference::length() const { return tail.size(); }
     328                 :             : 
     329                 :         270 : std::shared_ptr<json_lib::json> reference_lib::json_reference::value() {
     330   [ +  +  +  +  :         270 :     if (length() > 0 || head_type != ref_head_type::object) {
                   +  + ]
     331                 :          81 :         return shared_from_this();
     332                 :             :     }
     333         [ +  + ]:         189 :     if (head->type() != json_lib::json_type::reference_json) {
     334                 :         183 :         return head;
     335                 :             :     }
     336         [ +  - ]:           6 :     return std::dynamic_pointer_cast<json_reference>(head)->value();
     337                 :             : }
     338                 :             : 
     339                 :             : reference_lib::ref_head_type
     340                 :          18 : reference_lib::json_reference::get_head_type() const {
     341                 :          18 :     return head_type;
     342                 :             : }
     343                 :             : 
     344                 :          89 : void reference_lib::json_reference::simplify() {
     345   [ +  -  +  +  :         193 :     while (head_type == ref_head_type::object && length() > 0) {
                   +  + ]
     346                 :         116 :         auto accessor = tail.front();
     347   [ +  -  +  + ]:         116 :         if (head->type() == json_lib::json_type::reference_json) {
     348                 :           6 :             tail.pop_front();
     349                 :             :             const auto ref_head
     350                 :           6 :                 = std::dynamic_pointer_cast<json_reference>(head);
     351         [ +  - ]:           6 :             ref_head->emplace_back(accessor);
     352         [ +  - ]:           6 :             head = ref_head->value();
     353                 :           6 :         } else {
     354   [ +  -  +  + ]:         110 :             if (accessor->type() == json_lib::json_type::reference_json) {
     355                 :             :                 const auto ref_accessor
     356                 :          15 :                     = std::dynamic_pointer_cast<json_reference>(accessor);
     357   [ +  -  +  +  :          15 :                 switch (ref_accessor->reference_type()) {
                   -  - ]
     358                 :           9 :                 case json_reference_type::reference_json: {
     359         [ +  + ]:           9 :                     if (ref_accessor->get_head_type() == ref_head_type::root) {
     360                 :           6 :                         return;
     361                 :             :                     }
     362         [ +  - ]:           3 :                     ref_accessor->set_parent(head);
     363         [ +  - ]:           3 :                     tail.front() = ref_accessor->value();
     364                 :           3 :                     break;
     365                 :             :                 }
     366                 :           6 :                 case json_reference_type::set_json: {
     367                 :          12 :                     std::dynamic_pointer_cast<json_set>(ref_accessor)
     368         [ +  - ]:           6 :                         ->set_parent(head);
     369         [ +  - ]:           6 :                     head = ref_accessor->value();
     370                 :           6 :                     tail.pop_front();
     371                 :           6 :                     break;
     372                 :             :                 }
     373                 :           0 :                 case json_reference_type::function_json: {
     374                 :             :                     // todo
     375                 :           0 :                     return;
     376                 :             :                 }
     377                 :           0 :                 default: {
     378         [ #  # ]:           0 :                     throw std::runtime_error("unsupported accessor type");
     379                 :             :                 }
     380                 :             :                 }
     381         [ +  + ]:          15 :             } else {
     382         [ +  + ]:          95 :                 head = head->by(accessor);
     383                 :          89 :                 tail.pop_front();
     384                 :             :             }
     385                 :             :         }
     386         [ +  + ]:         116 :     }
     387                 :             : }
     388                 :             : 
     389                 :          14 : void reference_lib::json_reference::set_head_type(const ref_head_type type) {
     390                 :          14 :     head_type = type;
     391                 :          14 : }
        

Generated by: LCOV version 2.0-1