20 #include <daw/daw_algorithm.h>
21 #include <daw/daw_cxmath.h>
22 #include <daw/daw_parser_helper_sv.h>
23 #include <daw/daw_sort_n.h>
24 #include <daw/daw_string_view.h>
25 #include <daw/daw_traits.h>
26 #include <daw/daw_utility.h>
27 #include <daw/iterator/daw_back_inserter.h>
28 #include <daw/iterator/daw_inserter.h>
37 #include <string_view>
39 #include <type_traits>
43 template<JsonNullable>
48 using result_type = std::chrono::time_point<std::chrono::system_clock,
49 std::chrono::milliseconds>;
51 [[maybe_unused, nodiscard]]
inline constexpr
result_type
52 operator( )(
char const *ptr, std::size_t sz )
const {
60 std::optional<std::chrono::time_point<std::chrono::system_clock,
61 std::chrono::milliseconds>>;
63 [[maybe_unused, nodiscard]]
inline constexpr
result_type
64 operator( )( )
const {
68 [[maybe_unused, nodiscard]]
inline constexpr result_type
69 operator( )(
char const *ptr, std::size_t sz )
const {
76 [[nodiscard]]
inline constexpr decltype(
auto ) operator( )( ) {
77 if constexpr( std::is_same_v<T, std::string_view> or
78 std::is_same_v<T, std::optional<std::string_view>> ) {
79 return std::string_view{ };
81 return from_string( daw::tag<T> );
85 [[nodiscard]]
inline constexpr decltype(
auto )
86 operator( )( std::string_view sv ) {
87 if constexpr( std::is_same_v<T, std::string_view> or
88 std::is_same_v<T, std::optional<std::string_view>> ) {
91 return from_string( daw::tag<T>, sv );
97 namespace daw::json::json_details {
98 template<
typename, std::
size_t Lhs, std::
size_t Rhs>
99 struct are_equal : std::bool_constant<Lhs == Rhs> {};
101 template<
typename Container,
typename Value>
102 using can_insert1_test =
103 decltype( std::declval<Container &>( ).insert( std::declval<Value>( ) ) );
105 template<
typename Container,
typename Value>
106 inline constexpr
bool can_insert1_v =
107 daw::is_detected_v<can_insert1_test, Container, Value>;
109 template<
bool HashesColl
ide,
typename Range>
110 struct location_info_t {
111 UInt32 hash_value = 0_u32;
112 daw::string_view
const *name;
114 std::size_t count = 0;
116 explicit constexpr location_info_t( daw::string_view
const *Name )
120 [[maybe_unused, nodiscard]]
inline constexpr
bool missing( )
const {
121 return location.is_null( );
125 template<
typename Range>
126 struct location_info_t<false, Range> {
127 UInt32 hash_value = 0_u32;
128 typename Range::without_allocator_type location{ };
129 std::size_t count = 0;
131 explicit constexpr location_info_t( daw::string_view
const *Name )
134 [[maybe_unused, nodiscard]]
inline constexpr
bool missing( )
const {
135 return location.is_null( );
144 template<std::
size_t N,
typename Range,
bool HasCollisions = true>
145 struct locations_info_t {
146 using value_type = location_info_t<HasCollisions, Range>;
147 static constexpr
bool has_collisons = HasCollisions;
148 std::array<value_type, N> names;
150 constexpr location_info_t<HasCollisions, Range>
const &
151 operator[]( std::size_t idx )
const {
155 constexpr location_info_t<HasCollisions, Range> &
156 operator[]( std::size_t idx ) {
160 static constexpr std::size_t size( ) {
164 template<std::
size_t start_pos>
165 [[nodiscard]] constexpr std::size_t
166 find_name( daw::string_view key )
const {
168 #if defined( _MSC_VER ) and not defined( __clang__ )
171 for( std::size_t n = 0; n < N; ++n ) {
173 for( std::size_t n = start_pos; n < N; ++n ) {
175 if( names[n].hash_value == hash ) {
176 if constexpr( has_collisons ) {
188 template<
typename... MemberNames>
189 constexpr
bool do_hashes_collide( ) {
190 std::array<UInt32,
sizeof...( MemberNames )> hashes{
193 daw::sort( hashes.data( ), hashes.data( ) + hashes.size( ) );
194 return daw::algorithm::adjacent_find(
195 hashes.begin( ), hashes.end( ),
196 []( UInt32 l, UInt32 r ) { return l == r; } ) != hashes.end( );
199 template<
typename Range,
typename... JsonMembers>
200 constexpr
auto make_locations_info( ) {
201 constexpr
bool hashes_collide =
202 Range::force_name_equal_check or do_hashes_collide<JsonMembers...>( );
203 return locations_info_t<
sizeof...( JsonMembers ), Range, hashes_collide>{
204 location_info_t<hashes_collide, Range>( &JsonMembers::name )... };
218 template<std::size_t pos,
typename JsonMember, std::size_t N,
typename Range,
220 [[nodiscard]]
inline constexpr Range
221 find_class_member( locations_info_t<N, Range, B> &locations, Range &rng ) {
224 ( not locations[pos].missing( ) ) or
225 ( not rng.is_closing_brace_checked( ) ),
226 missing_member( JsonMember::name ), rng );
228 rng.trim_left_unchecked( );
230 while( locations[pos].missing( ) & ( rng.front( ) !=
'}' ) ) {
234 auto const name = parse_name( rng );
235 auto const name_pos = locations.template find_name<pos>( name );
236 if( name_pos >= locations.size( ) ) {
238 (void)skip_value( rng );
242 if( name_pos == pos ) {
243 locations[pos].location = Range::without_allocator( rng );
254 locations[name_pos].location = skip_value( rng ).without_allocator( );
259 return locations[pos].location.with_allocator( rng );
262 namespace pocm_details {
270 template<
typename Range>
271 constexpr
void maybe_skip_members( Range &rng,
272 std::size_t ¤t_position,
273 std::size_t desired_position ) {
279 ErrorReason::OutOfOrderOrderedMembers, rng );
280 while( current_position < desired_position and rng.front( ) !=
']' ) {
281 (void)skip_value( rng );
298 template<
typename JsonMember,
typename Range>
299 [[nodiscard]] DAW_ATTRIBUTE_FLATTEN
inline constexpr
auto
300 parse_ordered_class_member( std::size_t &member_position, Range &rng ) {
306 if constexpr( is_an_ordered_member_v<JsonMember> ) {
307 pocm_details::maybe_skip_members( rng, member_position,
308 JsonMember::member_index );
312 using json_member_type = ordered_member_subtype_t<JsonMember>;
317 if constexpr( is_json_nullable_v<ordered_member_subtype_t<JsonMember>> ) {
318 using constructor_t =
typename json_member_type::constructor_t;
319 return constructor_t{ }( );
320 }
else if constexpr( is_json_nullable_v<json_member_type> ) {
324 return parse_value<json_member_type>(
325 ParseTag<json_member_type::expected_type>{ }, rng );
338 template<std::size_t member_position,
typename JsonMember, std::size_t N,
339 typename Range,
bool B>
340 [[nodiscard]] DAW_ATTRIBUTE_FLATTEN
inline constexpr json_result<JsonMember>
341 parse_class_member( locations_info_t<N, Range, B> &locations, Range &rng ) {
343 static_assert( not is_no_name<JsonMember>,
344 "Array processing should never call parse_class_member" );
347 ErrorReason::MissingMemberNameOrEndOfClass, rng );
349 if constexpr( Range::has_allocator ) {
350 return find_class_member<member_position, JsonMember>( locations, rng )
351 .with_allocator( rng.get_allocator( ) );
353 return find_class_member<member_position, JsonMember>( locations, rng );
358 if( loc.first == rng.first ) {
359 return parse_value<JsonMember>( ParseTag<JsonMember::expected_type>{ },
362 if( not loc.is_null( ) ) {
363 return parse_value<JsonMember, true>(
364 ParseTag<JsonMember::expected_type>{ }, loc );
367 if constexpr( is_json_nullable_v<JsonMember> ) {
368 return parse_value<JsonMember, true>(
369 ParseTag<JsonMember::expected_type>{ }, loc );
372 JsonMember::name.data( ), JsonMember::name.size( ) ) ),
377 template<
typename Range>
378 DAW_ATTRIBUTE_FLATTEN
inline constexpr
void class_cleanup_now( Range &rng ) {
379 if( not rng.has_more( ) ) {
384 rng.move_to_next_class_member( );
385 (void)rng.skip_class( );
388 rng.trim_left_checked( );
398 template<
typename JsonClass,
typename... JsonMembers, std::size_t... Is,
400 [[nodiscard]]
inline constexpr JsonClass
401 parse_json_class( Range &rng, std::index_sequence<Is...> ) {
402 static_assert( has_json_data_contract_trait_v<JsonClass>,
407 ErrorReason::InvalidClassStart, rng );
408 rng.set_class_position( );
409 rng.remove_prefix( );
412 if constexpr(
sizeof...( JsonMembers ) == 0 ) {
414 class_cleanup_now( rng );
415 return construct_value<JsonClass>( json_class_constructor<JsonClass>,
419 #if not defined( _MSC_VER ) or defined( __clang__ )
422 constexpr
auto known_locations_v =
423 make_locations_info<Range, JsonMembers...>( );
425 auto known_locations = known_locations_v;
429 auto known_locations = make_locations_info<Range, JsonMembers...>( );
432 if constexpr( is_guaranteed_rvo_v<Range> ) {
436 #ifdef HAS_CPP20CONSTEXPR
437 if( std::is_constant_evaluated( ) ) {
439 if( std::uncaught_exceptions( ) == 0 ) {
440 class_cleanup_now( *rng_ptr );
442 #ifdef HAS_CPP20CONSTEXPR
444 class_cleanup_now( *rng_ptr );
448 }
const run_after_parse{ &rng };
449 (void)run_after_parse;
454 JsonClass>::value ) {
456 parse_class_member<Is, traits::nth_type<Is, JsonMembers...>>(
457 known_locations, rng )... };
460 using tp_t = decltype( std::forward_as_tuple(
461 parse_class_member<Is, traits::nth_type<Is, JsonMembers...>>(
462 known_locations, rng )... ) );
465 json_class_constructor<JsonClass>,
466 tp_t{ parse_class_member<Is, traits::nth_type<Is, JsonMembers...>>(
467 known_locations, rng )... } );
470 using tp_t = decltype( std::forward_as_tuple(
471 parse_class_member<Is, traits::nth_type<Is, JsonMembers...>>(
472 known_locations, rng )... ) );
473 JsonClass result = std::apply(
474 json_class_constructor<JsonClass>,
475 tp_t{ parse_class_member<Is, traits::nth_type<Is, JsonMembers...>>(
476 known_locations, rng )... } );
477 class_cleanup_now( rng );
487 template<
typename JsonClass,
typename... JsonMembers,
typename Range>
488 [[nodiscard]]
inline constexpr JsonClass
489 parse_ordered_json_class( Range &rng ) {
490 static_assert( has_json_data_contract_trait_v<JsonClass>,
493 std::is_invocable_v<json_class_constructor_t<JsonClass>,
494 typename JsonMembers::parse_to_t...>,
495 "Supplied types cannot be used for construction of this type" );
499 ErrorReason::InvalidArrayStart, rng );
500 rng.set_class_position( );
501 rng.remove_prefix( );
504 size_t current_idx = 0;
506 using tp_t = decltype( std::forward_as_tuple(
507 parse_ordered_class_member<JsonMembers>( current_idx, rng )... ) );
509 if constexpr( is_guaranteed_rvo_v<Range> ) {
513 #ifdef HAS_CPP20CONSTEXPR
514 if( std::is_constant_evaluated( ) ) {
516 if( std::uncaught_exceptions( ) == 0 ) {
517 (void)ptr->skip_array( );
519 #ifdef HAS_CPP20CONSTEXPR
521 (void)ptr->skip_array( );
525 }
const run_after_parse{ &rng };
526 (void)run_after_parse;
527 return std::apply( json_class_constructor<JsonClass>,
528 tp_t{ parse_ordered_class_member<JsonMembers>(
529 current_idx, rng )... } );
532 std::apply( json_class_constructor<JsonClass>,
533 tp_t{ parse_ordered_class_member<JsonMembers>( current_idx,
536 (void)rng.skip_array( );