100.00% Lines (244/244)
100.00% Functions (34/34)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com) | 2 | // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com) | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/boostorg/json | 7 | // Official repository: https://github.com/boostorg/json | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | #ifndef BOOST_JSON_IMPL_POINTER_IPP | 10 | #ifndef BOOST_JSON_IMPL_POINTER_IPP | |||||
| 11 | #define BOOST_JSON_IMPL_POINTER_IPP | 11 | #define BOOST_JSON_IMPL_POINTER_IPP | |||||
| 12 | 12 | |||||||
| 13 | #include <boost/json/value.hpp> | 13 | #include <boost/json/value.hpp> | |||||
| 14 | 14 | |||||||
| 15 | namespace boost { | 15 | namespace boost { | |||||
| 16 | namespace json { | 16 | namespace json { | |||||
| 17 | 17 | |||||||
| 18 | namespace detail { | 18 | namespace detail { | |||||
| 19 | 19 | |||||||
| 20 | class pointer_token | 20 | class pointer_token | |||||
| 21 | { | 21 | { | |||||
| 22 | public: | 22 | public: | |||||
| 23 | class iterator; | 23 | class iterator; | |||||
| 24 | 24 | |||||||
| HITCBC | 25 | 158 | pointer_token( | 25 | 158 | pointer_token( | ||
| 26 | string_view sv) noexcept | 26 | string_view sv) noexcept | |||||
| HITCBC | 27 | 158 | : b_( sv.begin() + 1 ) | 27 | 158 | : b_( sv.begin() + 1 ) | ||
| HITCBC | 28 | 158 | , e_( sv.end() ) | 28 | 158 | , e_( sv.end() ) | ||
| 29 | { | 29 | { | |||||
| HITCBC | 30 | 158 | BOOST_ASSERT( !sv.empty() ); | 30 | 158 | BOOST_ASSERT( !sv.empty() ); | ||
| HITCBC | 31 | 158 | BOOST_ASSERT( *sv.data() == '/' ); | 31 | 158 | BOOST_ASSERT( *sv.data() == '/' ); | ||
| HITCBC | 32 | 158 | } | 32 | 158 | } | ||
| 33 | 33 | |||||||
| 34 | iterator begin() const noexcept; | 34 | iterator begin() const noexcept; | |||||
| 35 | iterator end() const noexcept; | 35 | iterator end() const noexcept; | |||||
| 36 | 36 | |||||||
| 37 | private: | 37 | private: | |||||
| 38 | char const* b_; | 38 | char const* b_; | |||||
| 39 | char const* e_; | 39 | char const* e_; | |||||
| 40 | }; | 40 | }; | |||||
| 41 | 41 | |||||||
| 42 | class pointer_token::iterator | 42 | class pointer_token::iterator | |||||
| 43 | { | 43 | { | |||||
| 44 | public: | 44 | public: | |||||
| 45 | using value_type = char; | 45 | using value_type = char; | |||||
| 46 | using reference = char; | 46 | using reference = char; | |||||
| 47 | using pointer = value_type*; | 47 | using pointer = value_type*; | |||||
| 48 | using difference_type = std::ptrdiff_t; | 48 | using difference_type = std::ptrdiff_t; | |||||
| 49 | using iterator_category = std::forward_iterator_tag; | 49 | using iterator_category = std::forward_iterator_tag; | |||||
| 50 | 50 | |||||||
| HITCBC | 51 | 576 | explicit iterator(char const* base) noexcept | 51 | 576 | explicit iterator(char const* base) noexcept | ||
| HITCBC | 52 | 576 | : base_(base) | 52 | 576 | : base_(base) | ||
| 53 | { | 53 | { | |||||
| HITCBC | 54 | 576 | } | 54 | 576 | } | ||
| 55 | 55 | |||||||
| HITCBC | 56 | 625 | char operator*() const noexcept | 56 | 625 | char operator*() const noexcept | ||
| 57 | { | 57 | { | |||||
| HITCBC | 58 | 625 | switch( char c = *base_ ) | 58 | 625 | switch( char c = *base_ ) | ||
| 59 | { | 59 | { | |||||
| HITCBC | 60 | 2 | case '~': | 60 | 2 | case '~': | ||
| HITCBC | 61 | 2 | c = base_[1]; | 61 | 2 | c = base_[1]; | ||
| HITCBC | 62 | 2 | if( '0' == c ) | 62 | 2 | if( '0' == c ) | ||
| HITCBC | 63 | 1 | return '~'; | 63 | 1 | return '~'; | ||
| HITCBC | 64 | 1 | BOOST_ASSERT('1' == c); | 64 | 1 | BOOST_ASSERT('1' == c); | ||
| HITCBC | 65 | 1 | return '/'; | 65 | 1 | return '/'; | ||
| HITCBC | 66 | 623 | default: | 66 | 623 | default: | ||
| HITCBC | 67 | 623 | return c; | 67 | 623 | return c; | ||
| 68 | } | 68 | } | |||||
| 69 | } | 69 | } | |||||
| 70 | 70 | |||||||
| HITCBC | 71 | 827 | iterator& operator++() noexcept | 71 | 827 | iterator& operator++() noexcept | ||
| 72 | { | 72 | { | |||||
| HITCBC | 73 | 827 | if( '~' == *base_ ) | 73 | 827 | if( '~' == *base_ ) | ||
| HITCBC | 74 | 2 | base_ += 2; | 74 | 2 | base_ += 2; | ||
| 75 | else | 75 | else | |||||
| HITCBC | 76 | 825 | ++base_; | 76 | 825 | ++base_; | ||
| HITCBC | 77 | 827 | return *this; | 77 | 827 | return *this; | ||
| 78 | } | 78 | } | |||||
| 79 | 79 | |||||||
| HITCBC | 80 | 29 | iterator operator++(int) noexcept | 80 | 29 | iterator operator++(int) noexcept | ||
| 81 | { | 81 | { | |||||
| HITCBC | 82 | 29 | iterator result = *this; | 82 | 29 | iterator result = *this; | ||
| HITCBC | 83 | 29 | ++(*this); | 83 | 29 | ++(*this); | ||
| HITCBC | 84 | 29 | return result; | 84 | 29 | return result; | ||
| 85 | } | 85 | } | |||||
| 86 | 86 | |||||||
| HITCBC | 87 | 1678 | char const* base() const noexcept | 87 | 1678 | char const* base() const noexcept | ||
| 88 | { | 88 | { | |||||
| HITCBC | 89 | 1678 | return base_; | 89 | 1678 | return base_; | ||
| 90 | } | 90 | } | |||||
| 91 | 91 | |||||||
| 92 | private: | 92 | private: | |||||
| 93 | char const* base_; | 93 | char const* base_; | |||||
| 94 | }; | 94 | }; | |||||
| 95 | 95 | |||||||
| HITCBC | 96 | 619 | bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept | 96 | 619 | bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept | ||
| 97 | { | 97 | { | |||||
| HITCBC | 98 | 619 | return l.base() == r.base(); | 98 | 619 | return l.base() == r.base(); | ||
| 99 | } | 99 | } | |||||
| 100 | 100 | |||||||
| HITCBC | 101 | 220 | bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept | 101 | 220 | bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept | ||
| 102 | { | 102 | { | |||||
| HITCBC | 103 | 220 | return l.base() != r.base(); | 103 | 220 | return l.base() != r.base(); | ||
| 104 | } | 104 | } | |||||
| 105 | 105 | |||||||
| HITCBC | 106 | 288 | pointer_token::iterator pointer_token::begin() const noexcept | 106 | 288 | pointer_token::iterator pointer_token::begin() const noexcept | ||
| 107 | { | 107 | { | |||||
| HITCBC | 108 | 288 | return iterator(b_); | 108 | 288 | return iterator(b_); | ||
| 109 | } | 109 | } | |||||
| 110 | 110 | |||||||
| HITCBC | 111 | 288 | pointer_token::iterator pointer_token::end() const noexcept | 111 | 288 | pointer_token::iterator pointer_token::end() const noexcept | ||
| 112 | { | 112 | { | |||||
| HITCBC | 113 | 288 | return iterator(e_); | 113 | 288 | return iterator(e_); | ||
| 114 | } | 114 | } | |||||
| 115 | 115 | |||||||
| HITCBC | 116 | 249 | bool operator==(pointer_token token, string_view sv) noexcept | 116 | 249 | bool operator==(pointer_token token, string_view sv) noexcept | ||
| 117 | { | 117 | { | |||||
| HITCBC | 118 | 249 | auto t_b = token.begin(); | 118 | 249 | auto t_b = token.begin(); | ||
| HITCBC | 119 | 249 | auto const t_e = token.end(); | 119 | 249 | auto const t_e = token.end(); | ||
| HITCBC | 120 | 249 | auto s_b = sv.begin(); | 120 | 249 | auto s_b = sv.begin(); | ||
| HITCBC | 121 | 249 | auto const s_e = sv.end(); | 121 | 249 | auto const s_e = sv.end(); | ||
| HITCBC | 122 | 619 | while( s_b != s_e ) | 122 | 619 | while( s_b != s_e ) | ||
| 123 | { | 123 | { | |||||
| HITCBC | 124 | 474 | if( t_e == t_b ) | 124 | 474 | if( t_e == t_b ) | ||
| HITCBC | 125 | 4 | return false; | 125 | 4 | return false; | ||
| HITCBC | 126 | 470 | if( *t_b != *s_b ) | 126 | 470 | if( *t_b != *s_b ) | ||
| HITCBC | 127 | 100 | return false; | 127 | 100 | return false; | ||
| HITCBC | 128 | 370 | ++t_b; | 128 | 370 | ++t_b; | ||
| HITCBC | 129 | 370 | ++s_b; | 129 | 370 | ++s_b; | ||
| 130 | } | 130 | } | |||||
| HITCBC | 131 | 145 | return t_b == t_e; | 131 | 145 | return t_b == t_e; | ||
| 132 | } | 132 | } | |||||
| 133 | 133 | |||||||
| HITCBC | 134 | 72 | bool is_invalid_zero( | 134 | 72 | bool is_invalid_zero( | ||
| 135 | char const* b, | 135 | char const* b, | |||||
| 136 | char const* e) noexcept | 136 | char const* e) noexcept | |||||
| 137 | { | 137 | { | |||||
| 138 | // in JSON Pointer only zero index can start character '0' | 138 | // in JSON Pointer only zero index can start character '0' | |||||
| HITCBC | 139 | 72 | if( *b != '0' ) | 139 | 72 | if( *b != '0' ) | ||
| HITCBC | 140 | 56 | return false; | 140 | 56 | return false; | ||
| 141 | 141 | |||||||
| 142 | // if an index token starts with '0', then it should not have any more | 142 | // if an index token starts with '0', then it should not have any more | |||||
| 143 | // characters: either the string should end, or new token should start | 143 | // characters: either the string should end, or new token should start | |||||
| HITCBC | 144 | 16 | ++b; | 144 | 16 | ++b; | ||
| HITCBC | 145 | 16 | if( b == e ) | 145 | 16 | if( b == e ) | ||
| HITCBC | 146 | 13 | return false; | 146 | 13 | return false; | ||
| 147 | 147 | |||||||
| HITCBC | 148 | 3 | BOOST_ASSERT( *b != '/' ); | 148 | 3 | BOOST_ASSERT( *b != '/' ); | ||
| HITCBC | 149 | 3 | return true; | 149 | 3 | return true; | ||
| 150 | } | 150 | } | |||||
| 151 | 151 | |||||||
| HITCBC | 152 | 69 | bool is_past_the_end_token( | 152 | 69 | bool is_past_the_end_token( | ||
| 153 | char const* b, | 153 | char const* b, | |||||
| 154 | char const* e) noexcept | 154 | char const* e) noexcept | |||||
| 155 | { | 155 | { | |||||
| HITCBC | 156 | 69 | if( *b != '-' ) | 156 | 69 | if( *b != '-' ) | ||
| HITCBC | 157 | 57 | return false; | 157 | 57 | return false; | ||
| 158 | 158 | |||||||
| HITCBC | 159 | 12 | ++b; | 159 | 12 | ++b; | ||
| HITCBC | 160 | 12 | BOOST_ASSERT( (b == e) || (*b != '/') ); | 160 | 12 | BOOST_ASSERT( (b == e) || (*b != '/') ); | ||
| HITCBC | 161 | 12 | return b == e; | 161 | 12 | return b == e; | ||
| 162 | } | 162 | } | |||||
| 163 | 163 | |||||||
| 164 | std::size_t | 164 | std::size_t | |||||
| HITCBC | 165 | 75 | parse_number_token( | 165 | 75 | parse_number_token( | ||
| 166 | string_view sv, | 166 | string_view sv, | |||||
| 167 | system::error_code& ec) noexcept | 167 | system::error_code& ec) noexcept | |||||
| 168 | { | 168 | { | |||||
| HITCBC | 169 | 75 | BOOST_ASSERT( !sv.empty() ); | 169 | 75 | BOOST_ASSERT( !sv.empty() ); | ||
| 170 | 170 | |||||||
| HITCBC | 171 | 75 | char const* b = sv.begin(); | 171 | 75 | char const* b = sv.begin(); | ||
| HITCBC | 172 | 75 | BOOST_ASSERT( *b == '/' ); | 172 | 75 | BOOST_ASSERT( *b == '/' ); | ||
| 173 | 173 | |||||||
| HITCBC | 174 | 75 | ++b; | 174 | 75 | ++b; | ||
| HITCBC | 175 | 75 | char const* const e = sv.end(); | 175 | 75 | char const* const e = sv.end(); | ||
| HITCBC | 176 | 75 | if( ( b == e ) | 176 | 75 | if( ( b == e ) | ||
| HITCBC | 177 | 75 | || is_invalid_zero(b, e) ) | 177 | 75 | || is_invalid_zero(b, e) ) | ||
| 178 | { | 178 | { | |||||
| HITCBC | 179 | 6 | BOOST_JSON_FAIL(ec, error::token_not_number); | 179 | 6 | BOOST_JSON_FAIL(ec, error::token_not_number); | ||
| HITCBC | 180 | 6 | return {}; | 180 | 6 | return {}; | ||
| 181 | } | 181 | } | |||||
| 182 | 182 | |||||||
| HITCBC | 183 | 69 | if( is_past_the_end_token(b, e) ) | 183 | 69 | if( is_past_the_end_token(b, e) ) | ||
| 184 | { | 184 | { | |||||
| HITCBC | 185 | 10 | ++b; | 185 | 10 | ++b; | ||
| HITCBC | 186 | 10 | BOOST_JSON_FAIL(ec, error::past_the_end); | 186 | 10 | BOOST_JSON_FAIL(ec, error::past_the_end); | ||
| HITCBC | 187 | 10 | return {}; | 187 | 10 | return {}; | ||
| 188 | } | 188 | } | |||||
| 189 | 189 | |||||||
| HITCBC | 190 | 59 | std::size_t result = 0; | 190 | 59 | std::size_t result = 0; | ||
| HITCBC | 191 | 133 | for( ; b != e; ++b ) | 191 | 133 | for( ; b != e; ++b ) | ||
| 192 | { | 192 | { | |||||
| HITCBC | 193 | 104 | char const c = *b; | 193 | 104 | char const c = *b; | ||
| HITCBC | 194 | 104 | BOOST_ASSERT( c != '/' ); | 194 | 104 | BOOST_ASSERT( c != '/' ); | ||
| 195 | 195 | |||||||
| HITCBC | 196 | 104 | unsigned d = c - '0'; | 196 | 104 | unsigned d = c - '0'; | ||
| HITCBC | 197 | 104 | if( d > 9 ) | 197 | 104 | if( d > 9 ) | ||
| 198 | { | 198 | { | |||||
| HITCBC | 199 | 28 | BOOST_JSON_FAIL(ec, error::token_not_number); | 199 | 28 | BOOST_JSON_FAIL(ec, error::token_not_number); | ||
| HITCBC | 200 | 28 | return {}; | 200 | 28 | return {}; | ||
| 201 | } | 201 | } | |||||
| 202 | 202 | |||||||
| HITCBC | 203 | 76 | std::size_t new_result = result * 10 + d; | 203 | 76 | std::size_t new_result = result * 10 + d; | ||
| HITCBC | 204 | 76 | if( new_result < result ) | 204 | 76 | if( new_result < result ) | ||
| 205 | { | 205 | { | |||||
| HITCBC | 206 | 2 | BOOST_JSON_FAIL(ec, error::token_overflow); | 206 | 2 | BOOST_JSON_FAIL(ec, error::token_overflow); | ||
| HITCBC | 207 | 2 | return {}; | 207 | 2 | return {}; | ||
| 208 | } | 208 | } | |||||
| 209 | 209 | |||||||
| HITCBC | 210 | 74 | result = new_result; | 210 | 74 | result = new_result; | ||
| 211 | 211 | |||||||
| 212 | } | 212 | } | |||||
| HITCBC | 213 | 29 | return result; | 213 | 29 | return result; | ||
| 214 | } | 214 | } | |||||
| 215 | 215 | |||||||
| 216 | string_view | 216 | string_view | |||||
| HITCBC | 217 | 344 | next_segment( | 217 | 344 | next_segment( | ||
| 218 | string_view& sv, | 218 | string_view& sv, | |||||
| 219 | system::error_code& ec) noexcept | 219 | system::error_code& ec) noexcept | |||||
| 220 | { | 220 | { | |||||
| HITCBC | 221 | 344 | if( sv.empty() ) | 221 | 344 | if( sv.empty() ) | ||
| HITCBC | 222 | 108 | return sv; | 222 | 108 | return sv; | ||
| 223 | 223 | |||||||
| HITCBC | 224 | 236 | char const* const start = sv.begin(); | 224 | 236 | char const* const start = sv.begin(); | ||
| HITCBC | 225 | 236 | char const* b = start; | 225 | 236 | char const* b = start; | ||
| HITCBC | 226 | 236 | if( *b++ != '/' ) | 226 | 236 | if( *b++ != '/' ) | ||
| 227 | { | 227 | { | |||||
| HITCBC | 228 | 5 | BOOST_JSON_FAIL( ec, error::missing_slash ); | 228 | 5 | BOOST_JSON_FAIL( ec, error::missing_slash ); | ||
| HITCBC | 229 | 5 | return {}; | 229 | 5 | return {}; | ||
| 230 | } | 230 | } | |||||
| 231 | 231 | |||||||
| HITCBC | 232 | 231 | char const* e = sv.end(); | 232 | 231 | char const* e = sv.end(); | ||
| HITCBC | 233 | 768 | for( ; b < e; ++b ) | 233 | 768 | for( ; b < e; ++b ) | ||
| 234 | { | 234 | { | |||||
| HITCBC | 235 | 655 | char const c = *b; | 235 | 655 | char const c = *b; | ||
| HITCBC | 236 | 655 | if( '/' == c ) | 236 | 655 | if( '/' == c ) | ||
| HITCBC | 237 | 112 | break; | 237 | 112 | break; | ||
| 238 | 238 | |||||||
| HITCBC | 239 | 543 | if( '~' == c ) | 239 | 543 | if( '~' == c ) | ||
| 240 | { | 240 | { | |||||
| HITCBC | 241 | 8 | if( ++b == e ) | 241 | 8 | if( ++b == e ) | ||
| 242 | { | 242 | { | |||||
| HITCBC | 243 | 3 | BOOST_JSON_FAIL( ec, error::invalid_escape ); | 243 | 3 | BOOST_JSON_FAIL( ec, error::invalid_escape ); | ||
| HITCBC | 244 | 3 | break; | 244 | 3 | break; | ||
| 245 | } | 245 | } | |||||
| 246 | 246 | |||||||
| HITCBC | 247 | 5 | switch (*b) | 247 | 5 | switch (*b) | ||
| 248 | { | 248 | { | |||||
| HITCBC | 249 | 2 | case '0': // fall through | 249 | 2 | case '0': // fall through | ||
| 250 | case '1': | 250 | case '1': | |||||
| 251 | // valid escape sequence | 251 | // valid escape sequence | |||||
| HITCBC | 252 | 2 | continue; | 252 | 2 | continue; | ||
| HITCBC | 253 | 3 | default: { | 253 | 3 | default: { | ||
| HITCBC | 254 | 3 | BOOST_JSON_FAIL( ec, error::invalid_escape ); | 254 | 3 | BOOST_JSON_FAIL( ec, error::invalid_escape ); | ||
| HITCBC | 255 | 3 | break; | 255 | 3 | break; | ||
| 256 | } | 256 | } | |||||
| HITCBC | 257 | 2 | } | 257 | 2 | } | ||
| HITCBC | 258 | 3 | break; | 258 | 3 | break; | ||
| 259 | } | 259 | } | |||||
| 260 | } | 260 | } | |||||
| 261 | 261 | |||||||
| HITCBC | 262 | 231 | sv.remove_prefix( b - start ); | 262 | 231 | sv.remove_prefix( b - start ); | ||
| HITCBC | 263 | 231 | return string_view( start, b ); | 263 | 231 | return string_view( start, b ); | ||
| 264 | } | 264 | } | |||||
| 265 | 265 | |||||||
| 266 | value* | 266 | value* | |||||
| HITCBC | 267 | 125 | if_contains_token(object const& obj, pointer_token token) | 267 | 125 | if_contains_token(object const& obj, pointer_token token) | ||
| 268 | { | 268 | { | |||||
| HITCBC | 269 | 125 | if( obj.empty() ) | 269 | 125 | if( obj.empty() ) | ||
| HITCBC | 270 | 2 | return nullptr; | 270 | 2 | return nullptr; | ||
| 271 | 271 | |||||||
| HITCBC | 272 | 123 | auto const it = detail::find_in_object(obj, token).first; | 272 | 123 | auto const it = detail::find_in_object(obj, token).first; | ||
| HITCBC | 273 | 123 | if( !it ) | 273 | 123 | if( !it ) | ||
| HITCBC | 274 | 5 | return nullptr; | 274 | 5 | return nullptr; | ||
| 275 | 275 | |||||||
| HITCBC | 276 | 118 | return &it->value(); | 276 | 118 | return &it->value(); | ||
| 277 | } | 277 | } | |||||
| 278 | 278 | |||||||
| 279 | template< | 279 | template< | |||||
| 280 | class Value, | 280 | class Value, | |||||
| 281 | class OnObject, | 281 | class OnObject, | |||||
| 282 | class OnArray, | 282 | class OnArray, | |||||
| 283 | class OnScalar > | 283 | class OnScalar > | |||||
| 284 | Value* | 284 | Value* | |||||
| HITCBC | 285 | 129 | walk_pointer( | 285 | 129 | walk_pointer( | ||
| 286 | Value& jv, | 286 | Value& jv, | |||||
| 287 | string_view sv, | 287 | string_view sv, | |||||
| 288 | system::error_code& ec, | 288 | system::error_code& ec, | |||||
| 289 | OnObject on_object, | 289 | OnObject on_object, | |||||
| 290 | OnArray on_array, | 290 | OnArray on_array, | |||||
| 291 | OnScalar on_scalar) | 291 | OnScalar on_scalar) | |||||
| 292 | { | 292 | { | |||||
| HITCBC | 293 | 129 | ec.clear(); | 293 | 129 | ec.clear(); | ||
| 294 | 294 | |||||||
| HITCBC | 295 | 129 | string_view segment = detail::next_segment( sv, ec ); | 295 | 129 | string_view segment = detail::next_segment( sv, ec ); | ||
| 296 | 296 | |||||||
| HITCBC | 297 | 129 | Value* result = &jv; | 297 | 129 | Value* result = &jv; | ||
| HITCBC | 298 | 244 | while( true ) | 298 | 244 | while( true ) | ||
| 299 | { | 299 | { | |||||
| HITCBC | 300 | 373 | if( ec.failed() ) | 300 | 373 | if( ec.failed() ) | ||
| HITCBC | 301 | 43 | return nullptr; | 301 | 43 | return nullptr; | ||
| 302 | 302 | |||||||
| HITCBC | 303 | 330 | if( !result ) | 303 | 330 | if( !result ) | ||
| 304 | { | 304 | { | |||||
| HITCBC | 305 | 12 | BOOST_JSON_FAIL(ec, error::not_found); | 305 | 12 | BOOST_JSON_FAIL(ec, error::not_found); | ||
| HITCBC | 306 | 12 | return nullptr; | 306 | 12 | return nullptr; | ||
| 307 | } | 307 | } | |||||
| 308 | 308 | |||||||
| HITCBC | 309 | 318 | if( segment.empty() ) | 309 | 318 | if( segment.empty() ) | ||
| HITCBC | 310 | 74 | break; | 310 | 74 | break; | ||
| 311 | 311 | |||||||
| HITCBC | 312 | 244 | switch( result->kind() ) | 312 | 244 | switch( result->kind() ) | ||
| 313 | { | 313 | { | |||||
| HITCBC | 314 | 158 | case kind::object: { | 314 | 158 | case kind::object: { | ||
| HITCBC | 315 | 158 | auto& obj = result->get_object(); | 315 | 158 | auto& obj = result->get_object(); | ||
| 316 | 316 | |||||||
| HITCBC | 317 | 158 | detail::pointer_token const token( segment ); | 317 | 158 | detail::pointer_token const token( segment ); | ||
| HITCBC | 318 | 158 | segment = detail::next_segment( sv, ec ); | 318 | 158 | segment = detail::next_segment( sv, ec ); | ||
| 319 | 319 | |||||||
| HITCBC | 320 | 158 | result = on_object( obj, token ); | 320 | 158 | result = on_object( obj, token ); | ||
| HITCBC | 321 | 158 | break; | 321 | 158 | break; | ||
| 322 | } | 322 | } | |||||
| HITCBC | 323 | 57 | case kind::array: { | 323 | 57 | case kind::array: { | ||
| HITCBC | 324 | 57 | auto const index = detail::parse_number_token( segment, ec ); | 324 | 57 | auto const index = detail::parse_number_token( segment, ec ); | ||
| HITCBC | 325 | 57 | segment = detail::next_segment( sv, ec ); | 325 | 57 | segment = detail::next_segment( sv, ec ); | ||
| 326 | 326 | |||||||
| HITCBC | 327 | 57 | auto& arr = result->get_array(); | 327 | 57 | auto& arr = result->get_array(); | ||
| HITCBC | 328 | 57 | result = on_array( arr, index, ec ); | 328 | 57 | result = on_array( arr, index, ec ); | ||
| HITCBC | 329 | 57 | break; | 329 | 57 | break; | ||
| 330 | } | 330 | } | |||||
| HITCBC | 331 | 29 | default: { | 331 | 29 | default: { | ||
| HITCBC | 332 | 29 | if( on_scalar( *result, segment ) ) | 332 | 29 | if( on_scalar( *result, segment ) ) | ||
| HITCBC | 333 | 21 | break; | 333 | 21 | break; | ||
| HITCBC | 334 | 8 | BOOST_JSON_FAIL( ec, error::value_is_scalar ); | 334 | 8 | BOOST_JSON_FAIL( ec, error::value_is_scalar ); | ||
| 335 | }} | 335 | }} | |||||
| 336 | } | 336 | } | |||||
| 337 | 337 | |||||||
| HITCBC | 338 | 74 | BOOST_ASSERT( result ); | 338 | 74 | BOOST_ASSERT( result ); | ||
| HITCBC | 339 | 74 | return result; | 339 | 74 | return result; | ||
| 340 | } | 340 | } | |||||
| 341 | 341 | |||||||
| 342 | } // namespace detail | 342 | } // namespace detail | |||||
| 343 | 343 | |||||||
| 344 | value const& | 344 | value const& | |||||
| HITCBC | 345 | 56 | value::at_pointer(string_view ptr, source_location const& loc) const& | 345 | 56 | value::at_pointer(string_view ptr, source_location const& loc) const& | ||
| 346 | { | 346 | { | |||||
| HITCBC | 347 | 56 | return try_at_pointer(ptr).value(loc); | 347 | 56 | return try_at_pointer(ptr).value(loc); | ||
| 348 | } | 348 | } | |||||
| 349 | 349 | |||||||
| 350 | system::result<value const&> | 350 | system::result<value const&> | |||||
| HITCBC | 351 | 58 | value::try_at_pointer(string_view ptr) const noexcept | 351 | 58 | value::try_at_pointer(string_view ptr) const noexcept | ||
| 352 | { | 352 | { | |||||
| HITCBC | 353 | 58 | system::error_code ec; | 353 | 58 | system::error_code ec; | ||
| HITCBC | 354 | 58 | auto const found = find_pointer(ptr, ec); | 354 | 58 | auto const found = find_pointer(ptr, ec); | ||
| HITCBC | 355 | 58 | if( !found ) | 355 | 58 | if( !found ) | ||
| HITCBC | 356 | 10 | return ec; | 356 | 10 | return ec; | ||
| HITCBC | 357 | 48 | return *found; | 357 | 48 | return *found; | ||
| 358 | } | 358 | } | |||||
| 359 | 359 | |||||||
| 360 | system::result<value&> | 360 | system::result<value&> | |||||
| HITCBC | 361 | 2 | value::try_at_pointer(string_view ptr) noexcept | 361 | 2 | value::try_at_pointer(string_view ptr) noexcept | ||
| 362 | { | 362 | { | |||||
| HITCBC | 363 | 2 | system::error_code ec; | 363 | 2 | system::error_code ec; | ||
| HITCBC | 364 | 2 | auto const found = find_pointer(ptr, ec); | 364 | 2 | auto const found = find_pointer(ptr, ec); | ||
| HITCBC | 365 | 2 | if( !found ) | 365 | 2 | if( !found ) | ||
| HITCBC | 366 | 1 | return ec; | 366 | 1 | return ec; | ||
| HITCBC | 367 | 1 | return *found; | 367 | 1 | return *found; | ||
| 368 | } | 368 | } | |||||
| 369 | 369 | |||||||
| 370 | value const* | 370 | value const* | |||||
| HITCBC | 371 | 101 | value::find_pointer( string_view sv, system::error_code& ec ) const noexcept | 371 | 101 | value::find_pointer( string_view sv, system::error_code& ec ) const noexcept | ||
| 372 | { | 372 | { | |||||
| HITCBC | 373 | 101 | return detail::walk_pointer( | 373 | 101 | return detail::walk_pointer( | ||
| 374 | *this, | 374 | *this, | |||||
| 375 | sv, | 375 | sv, | |||||
| 376 | ec, | 376 | ec, | |||||
| HITCBC | 377 | 125 | []( object const& obj, detail::pointer_token token ) | 377 | 125 | []( object const& obj, detail::pointer_token token ) | ||
| 378 | { | 378 | { | |||||
| HITCBC | 379 | 125 | return detail::if_contains_token(obj, token); | 379 | 125 | return detail::if_contains_token(obj, token); | ||
| 380 | }, | 380 | }, | |||||
| HITCBC | 381 | 37 | []( array const& arr, std::size_t index, system::error_code& ec ) | 381 | 37 | []( array const& arr, std::size_t index, system::error_code& ec ) | ||
| 382 | -> value const* | 382 | -> value const* | |||||
| 383 | { | 383 | { | |||||
| HITCBC | 384 | 37 | if( ec ) | 384 | 37 | if( ec ) | ||
| HITCBC | 385 | 22 | return nullptr; | 385 | 22 | return nullptr; | ||
| 386 | 386 | |||||||
| HITCBC | 387 | 15 | return arr.if_contains(index); | 387 | 15 | return arr.if_contains(index); | ||
| 388 | }, | 388 | }, | |||||
| HITCBC | 389 | 5 | []( value const&, string_view) | 389 | 5 | []( value const&, string_view) | ||
| 390 | { | 390 | { | |||||
| HITCBC | 391 | 5 | return std::false_type(); | 391 | 5 | return std::false_type(); | ||
| HITCBC | 392 | 101 | }); | 392 | 101 | }); | ||
| 393 | } | 393 | } | |||||
| 394 | 394 | |||||||
| 395 | value* | 395 | value* | |||||
| HITCBC | 396 | 22 | value::find_pointer(string_view ptr, system::error_code& ec) noexcept | 396 | 22 | value::find_pointer(string_view ptr, system::error_code& ec) noexcept | ||
| 397 | { | 397 | { | |||||
| HITCBC | 398 | 22 | value const& self = *this; | 398 | 22 | value const& self = *this; | ||
| HITCBC | 399 | 22 | return const_cast<value*>(self.find_pointer(ptr, ec)); | 399 | 22 | return const_cast<value*>(self.find_pointer(ptr, ec)); | ||
| 400 | } | 400 | } | |||||
| 401 | 401 | |||||||
| 402 | value const* | 402 | value const* | |||||
| HITCBC | 403 | 20 | value::find_pointer(string_view ptr, std::error_code& ec) const noexcept | 403 | 20 | value::find_pointer(string_view ptr, std::error_code& ec) const noexcept | ||
| 404 | { | 404 | { | |||||
| HITCBC | 405 | 20 | system::error_code jec; | 405 | 20 | system::error_code jec; | ||
| HITCBC | 406 | 20 | value const* result = find_pointer(ptr, jec); | 406 | 20 | value const* result = find_pointer(ptr, jec); | ||
| HITCBC | 407 | 20 | ec = jec; | 407 | 20 | ec = jec; | ||
| HITCBC | 408 | 20 | return result; | 408 | 20 | return result; | ||
| 409 | } | 409 | } | |||||
| 410 | 410 | |||||||
| 411 | value* | 411 | value* | |||||
| HITCBC | 412 | 19 | value::find_pointer(string_view ptr, std::error_code& ec) noexcept | 412 | 19 | value::find_pointer(string_view ptr, std::error_code& ec) noexcept | ||
| 413 | { | 413 | { | |||||
| HITCBC | 414 | 19 | value const& self = *this; | 414 | 19 | value const& self = *this; | ||
| HITCBC | 415 | 19 | return const_cast<value*>(self.find_pointer(ptr, ec)); | 415 | 19 | return const_cast<value*>(self.find_pointer(ptr, ec)); | ||
| 416 | } | 416 | } | |||||
| 417 | 417 | |||||||
| 418 | value* | 418 | value* | |||||
| HITCBC | 419 | 28 | value::set_at_pointer( | 419 | 28 | value::set_at_pointer( | ||
| 420 | string_view sv, | 420 | string_view sv, | |||||
| 421 | value_ref ref, | 421 | value_ref ref, | |||||
| 422 | system::error_code& ec, | 422 | system::error_code& ec, | |||||
| 423 | set_pointer_options const& opts ) | 423 | set_pointer_options const& opts ) | |||||
| 424 | { | 424 | { | |||||
| HITCBC | 425 | 28 | value* result = detail::walk_pointer( | 425 | 28 | value* result = detail::walk_pointer( | ||
| 426 | *this, | 426 | *this, | |||||
| 427 | sv, | 427 | sv, | |||||
| 428 | ec, | 428 | ec, | |||||
| HITCBC | 429 | 33 | []( object& obj, detail::pointer_token token) | 429 | 33 | []( object& obj, detail::pointer_token token) | ||
| 430 | { | 430 | { | |||||
| HITCBC | 431 | 33 | if( !obj.empty() ) | 431 | 33 | if( !obj.empty() ) | ||
| 432 | { | 432 | { | |||||
| HITCBC | 433 | 13 | key_value_pair* kv = detail::find_in_object( obj, token ).first; | 433 | 13 | key_value_pair* kv = detail::find_in_object( obj, token ).first; | ||
| HITCBC | 434 | 13 | if( kv ) | 434 | 13 | if( kv ) | ||
| HITCBC | 435 | 12 | return &kv->value(); | 435 | 12 | return &kv->value(); | ||
| 436 | } | 436 | } | |||||
| 437 | 437 | |||||||
| HITCBC | 438 | 21 | string key( token.begin(), token.end(), obj.storage() ); | 438 | 21 | string key( token.begin(), token.end(), obj.storage() ); | ||
| HITCBC | 439 | 21 | return &obj.emplace( std::move(key), nullptr ).first->value(); | 439 | 21 | return &obj.emplace( std::move(key), nullptr ).first->value(); | ||
| HITCBC | 440 | 21 | }, | 440 | 21 | }, | ||
| HITCBC | 441 | 20 | [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value* | 441 | 20 | [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value* | ||
| 442 | { | 442 | { | |||||
| HITCBC | 443 | 20 | if( ec == error::past_the_end ) | 443 | 20 | if( ec == error::past_the_end ) | ||
| HITCBC | 444 | 6 | index = arr.size(); | 444 | 6 | index = arr.size(); | ||
| HITCBC | 445 | 14 | else if( ec.failed() ) | 445 | 14 | else if( ec.failed() ) | ||
| HITCBC | 446 | 2 | return nullptr; | 446 | 2 | return nullptr; | ||
| 447 | 447 | |||||||
| HITCBC | 448 | 18 | if( index >= arr.size() ) | 448 | 18 | if( index >= arr.size() ) | ||
| 449 | { | 449 | { | |||||
| HITCBC | 450 | 13 | std::size_t const n = index - arr.size(); | 450 | 13 | std::size_t const n = index - arr.size(); | ||
| HITCBC | 451 | 13 | if( n >= opts.max_created_elements ) | 451 | 13 | if( n >= opts.max_created_elements ) | ||
| HITCBC | 452 | 3 | return nullptr; | 452 | 3 | return nullptr; | ||
| 453 | 453 | |||||||
| HITCBC | 454 | 10 | arr.resize( arr.size() + n + 1 ); | 454 | 10 | arr.resize( arr.size() + n + 1 ); | ||
| 455 | } | 455 | } | |||||
| 456 | 456 | |||||||
| HITCBC | 457 | 15 | ec.clear(); | 457 | 15 | ec.clear(); | ||
| HITCBC | 458 | 15 | return arr.data() + index; | 458 | 15 | return arr.data() + index; | ||
| 459 | }, | 459 | }, | |||||
| HITCBC | 460 | 24 | [ &opts ]( value& jv, string_view segment ) | 460 | 24 | [ &opts ]( value& jv, string_view segment ) | ||
| 461 | { | 461 | { | |||||
| HITCBC | 462 | 24 | if( jv.is_null() || opts.replace_any_scalar ) | 462 | 24 | if( jv.is_null() || opts.replace_any_scalar ) | ||
| 463 | { | 463 | { | |||||
| HITCBC | 464 | 21 | if( opts.create_arrays ) | 464 | 21 | if( opts.create_arrays ) | ||
| 465 | { | 465 | { | |||||
| HITCBC | 466 | 18 | system::error_code ec; | 466 | 18 | system::error_code ec; | ||
| HITCBC | 467 | 18 | detail::parse_number_token( segment, ec ); | 467 | 18 | detail::parse_number_token( segment, ec ); | ||
| HITCBC | 468 | 18 | if( !ec.failed() || ec == error::past_the_end ) | 468 | 18 | if( !ec.failed() || ec == error::past_the_end ) | ||
| 469 | { | 469 | { | |||||
| HITCBC | 470 | 2 | jv = array( jv.storage() ); | 470 | 2 | jv = array( jv.storage() ); | ||
| HITCBC | 471 | 2 | return true; | 471 | 2 | return true; | ||
| 472 | } | 472 | } | |||||
| 473 | } | 473 | } | |||||
| 474 | 474 | |||||||
| HITCBC | 475 | 19 | if( opts.create_objects ) | 475 | 19 | if( opts.create_objects ) | ||
| 476 | { | 476 | { | |||||
| HITCBC | 477 | 19 | jv = object( jv.storage() ); | 477 | 19 | jv = object( jv.storage() ); | ||
| HITCBC | 478 | 19 | return true; | 478 | 19 | return true; | ||
| 479 | } | 479 | } | |||||
| 480 | } | 480 | } | |||||
| 481 | 481 | |||||||
| HITCBC | 482 | 3 | return false; | 482 | 3 | return false; | ||
| 483 | }); | 483 | }); | |||||
| 484 | 484 | |||||||
| HITCBC | 485 | 28 | if( result ) | 485 | 28 | if( result ) | ||
| HITCBC | 486 | 20 | *result = ref.make_value( storage() ); | 486 | 20 | *result = ref.make_value( storage() ); | ||
| HITCBC | 487 | 28 | return result; | 487 | 28 | return result; | ||
| 488 | } | 488 | } | |||||
| 489 | 489 | |||||||
| 490 | value* | 490 | value* | |||||
| HITCBC | 491 | 5 | value::set_at_pointer( | 491 | 5 | value::set_at_pointer( | ||
| 492 | string_view sv, | 492 | string_view sv, | |||||
| 493 | value_ref ref, | 493 | value_ref ref, | |||||
| 494 | std::error_code& ec, | 494 | std::error_code& ec, | |||||
| 495 | set_pointer_options const& opts ) | 495 | set_pointer_options const& opts ) | |||||
| 496 | { | 496 | { | |||||
| HITCBC | 497 | 5 | system::error_code jec; | 497 | 5 | system::error_code jec; | ||
| HITCBC | 498 | 5 | value* result = set_at_pointer( sv, ref, jec, opts ); | 498 | 5 | value* result = set_at_pointer( sv, ref, jec, opts ); | ||
| HITCBC | 499 | 5 | ec = jec; | 499 | 5 | ec = jec; | ||
| HITCBC | 500 | 5 | return result; | 500 | 5 | return result; | ||
| 501 | } | 501 | } | |||||
| 502 | 502 | |||||||
| 503 | system::result<value&> | 503 | system::result<value&> | |||||
| HITCBC | 504 | 18 | value::try_set_at_pointer( | 504 | 18 | value::try_set_at_pointer( | ||
| 505 | string_view sv, | 505 | string_view sv, | |||||
| 506 | value_ref ref, | 506 | value_ref ref, | |||||
| 507 | set_pointer_options const& opts ) | 507 | set_pointer_options const& opts ) | |||||
| 508 | { | 508 | { | |||||
| HITCBC | 509 | 18 | system::error_code ec; | 509 | 18 | system::error_code ec; | ||
| HITCBC | 510 | 18 | value* result = set_at_pointer( sv, ref, ec, opts ); | 510 | 18 | value* result = set_at_pointer( sv, ref, ec, opts ); | ||
| HITCBC | 511 | 18 | if( result ) | 511 | 18 | if( result ) | ||
| HITCBC | 512 | 16 | return *result; | 512 | 16 | return *result; | ||
| HITCBC | 513 | 2 | return ec; | 513 | 2 | return ec; | ||
| 514 | } | 514 | } | |||||
| 515 | 515 | |||||||
| 516 | value& | 516 | value& | |||||
| HITCBC | 517 | 17 | value::set_at_pointer( | 517 | 17 | value::set_at_pointer( | ||
| 518 | string_view sv, value_ref ref, set_pointer_options const& opts ) | 518 | string_view sv, value_ref ref, set_pointer_options const& opts ) | |||||
| 519 | { | 519 | { | |||||
| HITCBC | 520 | 17 | return try_set_at_pointer(sv, ref, opts).value(); | 520 | 17 | return try_set_at_pointer(sv, ref, opts).value(); | ||
| 521 | } | 521 | } | |||||
| 522 | 522 | |||||||
| 523 | } // namespace json | 523 | } // namespace json | |||||
| 524 | } // namespace boost | 524 | } // namespace boost | |||||
| 525 | 525 | |||||||
| 526 | #endif // BOOST_JSON_IMPL_POINTER_IPP | 526 | #endif // BOOST_JSON_IMPL_POINTER_IPP | |||||