DAW JSON Link
daw_json_parse_policy.h
Go to the documentation of this file.
1 // Copyright (c) Darrell Wright
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 // Official repository: https://github.com/beached/daw_json_link
7 //
8 
9 #pragma once
10 
11 #include "version.h"
12 
14 #include "daw_json_assert.h"
15 #include "daw_json_parse_common.h"
21 #include "daw_json_string_util.h"
22 
23 #include <daw/cpp_17.h>
24 #include <daw/daw_attributes.h>
25 #include <daw/daw_likely.h>
26 #include <daw/daw_traits.h>
27 
28 #include <cassert>
29 #include <cstddef>
30 #include <iterator>
31 #include <type_traits>
32 
33 namespace daw::json {
34  inline namespace DAW_JSON_VER {
45  template<json_options_t PolicyFlags = json_details::default_policy_flag,
46  typename Allocator = json_details::NoAllocator>
47  struct BasicParsePolicy : json_details::AllocatorWrapper<Allocator> {
48 
49  using i_am_a_parse_policy = void;
50  static constexpr bool is_default_parse_policy =
51  PolicyFlags == json_details::default_policy_flag and
52  std::is_same_v<Allocator, json_details::NoAllocator>;
53 
54  static DAW_CONSTEVAL json_options_t policy_flags( ) {
55  return PolicyFlags;
56  }
57 
58  using CharT = char const;
59  using iterator = CharT *;
60 
61  /***
62  * see options::CheckedParseMode
63  */
64  static constexpr bool is_unchecked_input =
65  json_details::get_bits_for<options::CheckedParseMode>( PolicyFlags ) ==
66  options::CheckedParseMode::no;
67 
68  /***
69  * See options::ExecModeTypes
70  */
71  using exec_tag_t =
72  switch_t<json_details::get_bits_for<options::ExecModeTypes,
73  std::size_t>( PolicyFlags ),
75 
76  static constexpr exec_tag_t exec_tag = exec_tag_t{ };
77 
78  /***
79  * see options::AllowEscapedNames
80  */
81  static constexpr bool allow_escaped_names =
82  json_details::get_bits_for<options::AllowEscapedNames>( PolicyFlags ) ==
83  options::AllowEscapedNames::yes;
84 
85  /***
86  * see options::ForceFullNameCheck
87  */
88  static constexpr bool force_name_equal_check =
89  json_details::get_bits_for<options::ForceFullNameCheck>(
90  PolicyFlags ) == options::ForceFullNameCheck::yes;
91 
92  /***
93  * see options::ZeroTerminatedString
94  */
95  static constexpr bool is_zero_terminated_string =
96  json_details::get_bits_for<options::ZeroTerminatedString>(
97  PolicyFlags ) == options::ZeroTerminatedString::yes;
98 
99  /***
100  * See options::IEEE754Precise
101  */
102  static constexpr bool precise_ieee754 =
103  json_details::get_bits_for<options::IEEE754Precise>( PolicyFlags ) ==
104  options::IEEE754Precise::yes;
105 
106  /***
107  * See options::MinifiedDocument
108  */
109  static constexpr bool minified_document =
110  json_details::get_bits_for<options::MinifiedDocument>( PolicyFlags ) ==
111  options::MinifiedDocument::yes;
112 
113  /***
114  * See options::ExcludeSpecialEscapes
115  */
116  static constexpr bool exclude_special_escapes =
117  json_details::get_bits_for<options::ExcludeSpecialEscapes>(
118  PolicyFlags ) == options::ExcludeSpecialEscapes::yes;
119 
121  static constexpr bool allow_leading_zero_plus = true;
122 
123  static constexpr bool use_exact_mappings_by_default =
124  json_details::get_bits_for<options::UseExactMappingsByDefault>(
125  PolicyFlags ) == options::UseExactMappingsByDefault::yes;
126 
127  static constexpr bool must_verify_end_of_data_is_valid =
128  json_details::get_bits_for<options::MustVerifyEndOfDataIsValid>(
129  PolicyFlags ) == options::MustVerifyEndOfDataIsValid::yes;
130 
131  static constexpr bool expect_long_strings =
132  json_details::get_bits_for<options::ExpectLongNames>( PolicyFlags ) ==
133  options::ExpectLongNames::yes;
134 
136  switch_t<json_details::get_bits_for<options::PolicyCommentTypes,
137  std::size_t>( PolicyFlags ),
140 
141  iterator first{ };
142  iterator last{ };
143  iterator class_first{ };
144  iterator class_last{ };
145  std::size_t counter = 0;
146 
147  template<auto... PolicyOptions>
149  json_details::set_bits( PolicyFlags, PolicyOptions... ), Allocator>;
150 
151  explicit BasicParsePolicy( ) = default;
152 
153  explicit constexpr BasicParsePolicy( iterator f, iterator l )
154  : first( f )
155  , last( l )
156  , class_first( f )
157  , class_last( l ) {}
158 
159  explicit constexpr BasicParsePolicy( iterator f, iterator l,
160  Allocator &alloc )
161  : json_details::AllocatorWrapper<Allocator>( alloc )
162  , first( f )
163  , last( l )
164  , class_first( f )
165  , class_last( l ) {}
166 
167  explicit constexpr BasicParsePolicy( iterator f, iterator l, iterator cf,
168  iterator cl )
169  : first( f )
170  , last( l )
171  , class_first( cf )
172  , class_last( cl ) {}
173 
174  explicit constexpr BasicParsePolicy( iterator f, iterator l, iterator cf,
175  iterator cl, Allocator const &alloc )
176  : json_details::AllocatorWrapper<Allocator>( alloc )
177  , first( f )
178  , last( l )
179  , class_first( cf )
180  , class_last( cl ) {}
181 
182  [[nodiscard]] constexpr BasicParsePolicy
183  copy( iterator f = iterator{ }, iterator l = iterator{ },
184  iterator cf = iterator{ }, iterator cl = iterator{ } ) const {
185  BasicParsePolicy result = *this;
186  if( f ) {
187  result.first = f;
188  }
189  if( l ) {
190  result.last = l;
191  }
192  if( cf ) {
193  result.class_first = cf;
194  }
195  if( cl ) {
196  result.class_last = cl;
197  }
198  return result;
199  }
200 
201  DAW_ATTRIB_INLINE constexpr decltype( auto ) get_allocator( ) const {
202  return json_details::AllocatorWrapper<Allocator>::get_allocator( );
203  }
204 
205  template<typename Alloc>
207 
208  template<typename Alloc>
209  [[nodiscard]] static constexpr with_allocator_type<Alloc>
211  Alloc const &alloc ) {
212  return with_allocator_type<Alloc>{ f, l, cf, cl, alloc };
213  }
214 
215  [[nodiscard]] static constexpr BasicParsePolicy
217  json_details::NoAllocator const & ) {
218  return BasicParsePolicy( f, l, cf, cl );
219  }
220 
221  template<typename Alloc>
222  [[nodiscard]] constexpr auto
224  if constexpr( std::is_same_v<Alloc, json_details::NoAllocator> ) {
225  return *this;
226  } else {
227  auto result = with_allocator( first, last, class_first, class_last,
228  p.get_allocator( ) );
229  result.counter = p.counter;
230  return result;
231  }
232  }
233 
234  template<typename Alloc>
235  [[nodiscard]] constexpr with_allocator_type<Alloc>
236  with_allocator( Alloc const &alloc ) const {
237  auto result =
238  with_allocator( first, last, class_first, class_last, alloc );
239  result.counter = counter;
240  return result;
241  }
242 
243  [[nodiscard]] DAW_ATTRIB_INLINE constexpr auto
244  with_allocator( json_details::NoAllocator const & ) const {
245  return *this;
246  }
247 
250 
251  template<typename Alloc>
252  [[nodiscard]] static constexpr with_allocator_type<Alloc>
253  with_allocator( iterator f, iterator l, Alloc const &alloc ) {
254  return { f, l, f, l, alloc };
255  }
256 
257  template<typename Alloc>
258  [[nodiscard]] static constexpr BasicParsePolicy
260  json_details::NoAllocator const & ) {
261  return { f, l, f, l };
262  }
263 
264  [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator data( ) const {
265  return first;
266  }
267 
268  [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator data_end( ) const {
269  return last;
270  }
271 
272  [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator begin( ) const {
273  return first;
274  }
275 
276  [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator end( ) const {
277  return last;
278  }
279 
280  [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool empty( ) const {
281  if( not first ) {
282  return true;
283  }
284  if constexpr( is_zero_terminated_string ) {
285  return first >= last or *first == '\0';
286  } else {
287  return first >= last;
288  }
289  }
290 
291  [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool has_more( ) const {
292  return first < last;
293  }
294 
295  template<std::size_t N>
296  constexpr bool starts_with( char const ( &rhs )[N] ) const {
297  static_assert( N > 0 );
298  if( size( ) < ( N - 1 ) ) {
299  return false;
300  }
301  bool result = true;
302  for( std::size_t n = 0; n < ( N - 1 ); ++n ) {
303  result = result & ( first[n] == rhs[n] );
304  }
305  return result;
306  }
307 
308  template<char c>
309  DAW_ATTRIB_INLINE constexpr void move_to_next_of_unchecked( ) {
310  first =
311  json_details::memchr_unchecked<c, exec_tag_t, expect_long_strings>(
312  first, last );
313  }
314 
315  template<char c>
316  DAW_ATTRIB_INLINE constexpr void move_to_next_of_checked( ) {
317  first =
318  json_details::memchr_checked<c, exec_tag_t, expect_long_strings>(
319  first, last );
320  }
321 
322  template<char c>
323  DAW_ATTRIB_INLINE constexpr void move_to_next_of( ) {
324  if( is_unchecked_input ) {
325  move_to_next_of_unchecked<c>( );
326  } else {
327  move_to_next_of_checked<c>( );
328  }
329  }
330 
331  [[nodiscard]] DAW_ATTRIB_INLINE constexpr char front( ) const {
332  return *first;
333  }
334 
335  [[nodiscard]] DAW_ATTRIB_INLINE constexpr char front_checked( ) const {
336  daw_json_ensure( first < last, ErrorReason::UnexpectedEndOfData,
337  *this );
338  return *first;
339  }
340 
341  [[nodiscard]] DAW_ATTRIB_INLINE constexpr std::size_t size( ) const {
342  assert( last >= first );
343  return static_cast<std::size_t>( last - first );
344  }
345 
346  [[nodiscard]] constexpr bool is_null( ) const {
347  return first == nullptr;
348  }
349 
350  DAW_ATTRIB_INLINE constexpr void remove_prefix( ) {
351  ++first;
352  }
353 
354  DAW_ATTRIB_INLINE constexpr void remove_prefix( std::size_t n ) {
355  first += static_cast<std::ptrdiff_t>( n );
356  }
357 
358  constexpr void set_class_position( ) {
359  class_first = first;
360  class_last = last;
361  }
362 
363  struct class_pos_t {
366  };
367 
368  constexpr void set_class_position( class_pos_t new_pos ) {
369  class_first = new_pos.f;
370  class_last = new_pos.l;
371  }
372 
373  [[nodiscard]] constexpr class_pos_t get_class_position( ) const {
374  return { class_first, class_last };
375  }
376 
377  constexpr void trim_left_checked( ) {
378  return CommentPolicy::trim_left_checked( *this );
379  }
380 
381  constexpr void trim_left_unchecked( ) {
382  return CommentPolicy::trim_left_unchecked( *this );
383  }
384 
385  [[nodiscard]] constexpr bool is_literal_end( ) const {
386  return CommentPolicy::is_literal_end( *first );
387  }
388 
389  [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool
391  return ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
392  1U ) <= 0x1FU;
393  }
394 
395  [[nodiscard]] constexpr bool is_opening_bracket_checked( ) const {
396  return DAW_LIKELY( first < last ) and *first == '[';
397  }
398 
399  [[nodiscard]] constexpr bool is_opening_brace_checked( ) const {
400  return DAW_LIKELY( first < last ) and *first == '{';
401  }
402 
403  [[nodiscard]] constexpr bool is_closing_brace_checked( ) const {
404  return DAW_LIKELY( first < last ) and *first == '}';
405  }
406 
407  [[nodiscard]] constexpr bool is_quotes_checked( ) const {
408  return DAW_LIKELY( first < last ) and *first == '"';
409  }
410 
411  DAW_ATTRIB_INLINE constexpr void trim_left( ) {
412  if constexpr( is_unchecked_input ) {
413  trim_left_unchecked( );
414  } else {
415  trim_left_checked( );
416  }
417  }
418 
419  constexpr void move_next_member_or_end_unchecked( ) {
420  trim_left_unchecked( );
421  if( *first == ',' ) {
422  ++first;
423  trim_left_unchecked( );
424  }
425  }
426 
427  DAW_ATTRIB_FLATINLINE inline constexpr void
429  trim_left_checked( );
430  if constexpr( is_zero_terminated_string ) {
431  if( *first == ',' ) {
432  ++first;
433  trim_left( );
434  }
435  } else {
436  if( DAW_LIKELY( first < last ) and *first == ',' ) {
437  ++first;
438  trim_left( );
439  }
440  }
441  }
442 
443  DAW_ATTRIB_INLINE constexpr void move_next_member_or_end( ) {
444  if constexpr( is_unchecked_input ) {
445  move_next_member_or_end_unchecked( );
446  } else {
447  move_next_member_or_end_checked( );
448  }
449  }
450 
451  DAW_ATTRIB_INLINE constexpr void move_next_member( ) {
452  if constexpr( is_unchecked_input ) {
453  CommentPolicy::move_next_member_unchecked( *this );
454  } else {
455  // We have no guarantee that all members are available
456  move_next_member_or_end_checked( );
457  }
458  }
459 
460  constexpr void move_to_next_class_member( ) {
461  CommentPolicy::template move_to_next_of<'"', '}'>( *this );
462  }
463 
464  [[nodiscard]] constexpr bool is_at_next_class_member( ) const {
465  return parse_policy_details::in<'"', '}'>( *first );
466  }
467 
468  [[nodiscard]] constexpr bool is_at_next_array_element( ) const {
469  return parse_policy_details::in<',', ']'>( *first );
470  }
471 
472  [[nodiscard]] constexpr bool is_at_token_after_value( ) const {
473  return parse_policy_details::in<',', '}', ']'>( *first );
474  }
475 
476  template<char PrimLeft>
477  [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy
479  return CommentPolicy::template skip_bracketed_item_checked<PrimLeft>(
480  *this );
481  }
482 
483  template<char PrimLeft>
484  [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy
486  return CommentPolicy::template skip_bracketed_item_unchecked<PrimLeft>(
487  *this );
488  }
489 
490  [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy skip_class( ) {
491  if constexpr( is_unchecked_input ) {
492  return skip_bracketed_item_unchecked<'{'>( );
493  } else {
494  return skip_bracketed_item_checked<'{'>( );
495  }
496  }
497 
498  [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy skip_array( ) {
499  if constexpr( is_unchecked_input ) {
500  return skip_bracketed_item_unchecked<'['>( );
501  } else {
502  return skip_bracketed_item_checked<'['>( );
503  }
504  }
505  };
506 
508 
509  BasicParsePolicy( char const *, char const * ) -> BasicParsePolicy<>;
510 
511  template<typename Allocator>
512  BasicParsePolicy( char const *, char const *, Allocator const & )
514 
515  BasicParsePolicy( char const *, char const *, char const *, char const * )
517 
518  template<typename Allocator>
519  BasicParsePolicy( char const *, char const *, char const *, char const *,
520  Allocator const & )
522 
524  : BasicParsePolicy<json_details::default_policy_flag,
525  json_details::NoAllocator> {
526 
528 
529  constexpr DefaultParsePolicy( BasicParsePolicy const &other ) noexcept
530  : BasicParsePolicy( other ) {}
531  constexpr DefaultParsePolicy( BasicParsePolicy &&other ) noexcept
532  : BasicParsePolicy( std::move( other ) ) {}
533  };
534 
535  template<json_options_t PolicyFlags = json_details::default_policy_flag,
536  typename Allocator = json_details::NoAllocator>
538  daw::conditional_t<(PolicyFlags == json_details::default_policy_flag and
539  std::is_same_v<Allocator, json_details::NoAllocator>),
542  template<typename ParsePolicy>
544  daw::conditional_t<ParsePolicy::is_default_parse_policy,
545  DefaultParsePolicy, ParsePolicy>;
546 
547  namespace options {
548  /***
549  * @brief Specify parse policy flags in to_json calls. See cookbook item
550  * parse_options.md
551  */
552  template<auto... PolicyFlags>
553  struct parse_flags_t {
554  static_assert(
555  json_details::are_option_flags<decltype( PolicyFlags )...>,
556  "Only registered policy types are allowed" );
557  static constexpr json_options_t value = parse_options( PolicyFlags... );
558  };
559  template<>
560  struct parse_flags_t<> {
561  static constexpr json_options_t value =
562  json_details::default_policy_flag;
563  };
564 
565  namespace details {
566  template<typename... Ts>
567  std::false_type is_policy_flag( Ts... );
568 
569  template<auto... PolicyFlags>
571 
572  template<auto... PolicyFlags>
573  DAW_CONSTEVAL auto make_parse_flags( ) {
574  if constexpr( decltype( details::is_policy_flag(
575  PolicyFlags... ) )::value ) {
576  static_assert( sizeof...( PolicyFlags ) == 1 );
577  // We know there is only one but need to unpack
578  return ( PolicyFlags, ... );
579  } else {
580  return parse_flags_t<PolicyFlags...>{ };
581  }
582  }
583  } // namespace details
588  template<auto... PolicyFlags>
589  inline constexpr auto parse_flags =
590  details::make_parse_flags<PolicyFlags...>( );
591  } // namespace options
592 
593 #define DAW_JSON_CONFORMANCE_FLAGS \
594  daw::json::options::AllowEscapedNames::yes, \
595  daw::json::options::MustVerifyEndOfDataIsValid::yes, \
596  daw::json::options::IEEE754Precise::yes, \
597  daw::json::options::ExcludeSpecialEscapes::yes
598 
599  inline constexpr auto ConformancePolicy =
600  options::parse_flags<DAW_JSON_CONFORMANCE_FLAGS>;
601 
602  } // namespace DAW_JSON_VER
603 } // namespace daw::json
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
PolicyCommentTypes
Allow comments in JSON. The supported modes are none, C++ style comments, and # hash style comments....
ExecModeTypes
Allow for different optimizations. Currently only the compile_time path is fully supported....
std::true_type is_policy_flag(parse_flags_t< PolicyFlags... >)
constexpr auto parse_flags
Specify parse policy flags in to_json calls. See cookbook item parse_options.md.
daw::conditional_t<(PolicyFlags==json_details::default_policy_flag and std::is_same_v< Allocator, json_details::NoAllocator >), DefaultParsePolicy, BasicParsePolicy< PolicyFlags, Allocator > > GetParsePolicy
BasicParsePolicy(char const *, char const *, char const *, char const *, Allocator const &) -> BasicParsePolicy< json_details::default_policy_flag, Allocator >
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
Customization point traits.
Handles the bounds and policy items for parsing execution and comments.
constexpr DAW_ATTRIB_INLINE BasicParsePolicy skip_bracketed_item_unchecked()
static constexpr with_allocator_type< Alloc > with_allocator(iterator f, iterator l, Alloc const &alloc)
static constexpr BasicParsePolicy with_allocator(iterator f, iterator l, iterator cf, iterator cl, json_details::NoAllocator const &)
switch_t< json_details::get_bits_for< options::ExecModeTypes, std::size_t >(PolicyFlags), constexpr_exec_tag, runtime_exec_tag, simd_exec_tag > exec_tag_t
static constexpr with_allocator_type< Alloc > with_allocator(iterator f, iterator l, iterator cf, iterator cl, Alloc const &alloc)
constexpr auto with_allocator(BasicParsePolicy< PolicyFlags, Alloc > p) const
static constexpr BasicParsePolicy with_allocator(iterator f, iterator l, json_details::NoAllocator const &)
constexpr BasicParsePolicy copy(iterator f=iterator{ }, iterator l=iterator{ }, iterator cf=iterator{ }, iterator cl=iterator{ }) const
constexpr DAW_ATTRIB_INLINE auto with_allocator(json_details::NoAllocator const &) const
constexpr with_allocator_type< Alloc > with_allocator(Alloc const &alloc) const
switch_t< json_details::get_bits_for< options::PolicyCommentTypes, std::size_t >(PolicyFlags), NoCommentSkippingPolicy, CppCommentSkippingPolicy, HashCommentSkippingPolicy > CommentPolicy
constexpr DAW_ATTRIB_INLINE BasicParsePolicy skip_bracketed_item_checked()
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25