pointer.ipp 11 KB

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