pointer.ipp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. //
  2. // Copyright (c) 2022 Dmitry Arkhipov ([email protected])
  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) const&
  291. {
  292. system::error_code ec;
  293. auto const found = find_pointer(ptr, ec);
  294. if( !found )
  295. detail::throw_system_error( ec );
  296. return *found;
  297. }
  298. value const*
  299. value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
  300. {
  301. return detail::walk_pointer(
  302. *this,
  303. sv,
  304. ec,
  305. []( object const& obj, detail::pointer_token token )
  306. {
  307. return detail::if_contains_token(obj, token);
  308. },
  309. []( array const& arr, std::size_t index, system::error_code& ec )
  310. -> value const*
  311. {
  312. if( ec )
  313. return nullptr;
  314. return arr.if_contains(index);
  315. },
  316. []( value const&, string_view)
  317. {
  318. return std::false_type();
  319. });
  320. }
  321. value*
  322. value::find_pointer(string_view ptr, system::error_code& ec) noexcept
  323. {
  324. value const& self = *this;
  325. return const_cast<value*>(self.find_pointer(ptr, ec));
  326. }
  327. value const*
  328. value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
  329. {
  330. system::error_code jec;
  331. value const* result = find_pointer(ptr, jec);
  332. ec = jec;
  333. return result;
  334. }
  335. value*
  336. value::find_pointer(string_view ptr, std::error_code& ec) noexcept
  337. {
  338. value const& self = *this;
  339. return const_cast<value*>(self.find_pointer(ptr, ec));
  340. }
  341. value*
  342. value::set_at_pointer(
  343. string_view sv,
  344. value_ref ref,
  345. system::error_code& ec,
  346. set_pointer_options const& opts )
  347. {
  348. value* result = detail::walk_pointer(
  349. *this,
  350. sv,
  351. ec,
  352. []( object& obj, detail::pointer_token token)
  353. {
  354. if( !obj.empty() )
  355. {
  356. key_value_pair* kv = detail::find_in_object( obj, token ).first;
  357. if( kv )
  358. return &kv->value();
  359. }
  360. string key( token.begin(), token.end(), obj.storage() );
  361. return &obj.emplace( std::move(key), nullptr ).first->value();
  362. },
  363. [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
  364. {
  365. if( ec == error::past_the_end )
  366. index = arr.size();
  367. else if( ec.failed() )
  368. return nullptr;
  369. if( index >= arr.size() )
  370. {
  371. std::size_t const n = index - arr.size();
  372. if( n >= opts.max_created_elements )
  373. return nullptr;
  374. arr.resize( arr.size() + n + 1 );
  375. }
  376. ec.clear();
  377. return arr.data() + index;
  378. },
  379. [ &opts ]( value& jv, string_view segment )
  380. {
  381. if( jv.is_null() || opts.replace_any_scalar )
  382. {
  383. if( opts.create_arrays )
  384. {
  385. system::error_code ec;
  386. detail::parse_number_token( segment, ec );
  387. if( !ec.failed() || ec == error::past_the_end )
  388. {
  389. jv = array( jv.storage() );
  390. return true;
  391. }
  392. }
  393. if( opts.create_objects )
  394. {
  395. jv = object( jv.storage() );
  396. return true;
  397. }
  398. }
  399. return false;
  400. });
  401. if( result )
  402. *result = ref.make_value( storage() );
  403. return result;
  404. }
  405. value*
  406. value::set_at_pointer(
  407. string_view sv,
  408. value_ref ref,
  409. std::error_code& ec,
  410. set_pointer_options const& opts )
  411. {
  412. system::error_code jec;
  413. value* result = set_at_pointer( sv, ref, jec, opts );
  414. ec = jec;
  415. return result;
  416. }
  417. value&
  418. value::set_at_pointer(
  419. string_view sv, value_ref ref, set_pointer_options const& opts )
  420. {
  421. system::error_code ec;
  422. value* result = set_at_pointer( sv, ref, ec, opts );
  423. if( !result )
  424. detail::throw_system_error( ec );
  425. return *result;
  426. }
  427. } // namespace json
  428. } // namespace boost
  429. #endif // BOOST_JSON_IMPL_POINTER_IPP