DAW JSON Link
Loading...
Searching...
No Matches
daw_json_value_state.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 "impl/version.h"
12
16#include "impl/daw_json_value.h"
17#include "impl/daw_murmur3.h"
18
19#include <daw/daw_move.h>
20#include <daw/daw_string_view.h>
21#include <daw/daw_uint_buffer.h>
22
23#include <cstddef>
24#include <string_view>
25#include <utility>
26#include <vector>
27
28namespace daw::json {
29 inline namespace DAW_JSON_VER {
30 namespace json_details {
31 template<json_options_t PolicyFlags = default_policy_flag,
32 typename Allocator = NoAllocator>
33 class basic_stateful_json_value_state {
34 using ParseState =
36
37 public:
38 daw::string_view name;
39 daw::UInt32 hash_value;
41
42 explicit constexpr basic_stateful_json_value_state(
43 daw::string_view Name,
45 : name( Name )
46 , hash_value(
47 daw::name_hash<ParseState::expect_long_strings>( Name ) )
48 , location( std::move( val ) ) {}
49
50 [[nodiscard]] constexpr bool is_match( daw::string_view Name ) const {
51 return name == Name;
52 }
53
54 [[nodiscard]] constexpr bool is_match( daw::string_view Name,
55 daw::UInt32 hash ) const {
56 if( hash != hash_value ) {
57 return false;
58 }
59 return name == Name;
60 }
61 };
62 } // namespace json_details
63
65 daw::string_view name;
66 daw::UInt32 hash_value;
67
68 constexpr json_member_name( std::string_view Name )
69 : name( std::data( Name ), std::size( Name ) )
70 , hash_value( daw::name_hash<false>( name ) ) {}
71 };
72
78 template<json_options_t PolicyFlags = json_details::default_policy_flag,
79 typename Allocator = json_details::NoAllocator>
81 using ParseState =
83
85 std::vector<
86 json_details::basic_stateful_json_value_state<PolicyFlags, Allocator>>
87 m_locs{ };
88
89 /***
90 * Move parser until member name matches key if needed
91 * @param member to move_to
92 * @return position of member or size
93 */
94 [[nodiscard]] constexpr std::size_t move_to( json_member_name member ) {
95 std::size_t pos = 0;
96 std::size_t const Sz = std::size( m_locs );
97 for( ; pos < Sz; ++pos ) {
98 if( m_locs[pos].is_match( member.name, member.hash_value ) ) {
99 return pos;
100 }
101 }
102
103 auto it = [&] {
104 if( m_locs.empty( ) ) {
105 return m_value.begin( );
106 }
107 auto res = m_locs.back( ).location;
108 ++res;
109 return res;
110 }( );
111 auto const last = m_value.end( );
112 while( it != last ) {
113 auto name = it.name( );
114 daw_json_assert_weak( name, ErrorReason::MissingMemberName );
115 auto const &new_loc = m_locs.emplace_back(
116 daw::string_view( std::data( *name ), std::size( *name ) ), it );
117 if( new_loc.is_match( member.name ) ) {
118 return pos;
119 }
120 ++pos;
121 ++it;
122 }
123 return std::size( m_locs );
124 }
125
126 /***
127 * Move parser until member index matches, if needed
128 * @param index position of member to move to
129 * @return position in members or size
130 */
131 [[nodiscard]] constexpr std::size_t move_to( std::size_t index ) {
132 if( index < std::size( m_locs ) ) {
133 return index;
134 }
135 auto it = [&] {
136 if( m_locs.empty( ) ) {
137 return m_value.begin( );
138 }
139 auto res = m_locs.back( ).location;
140 ++res;
141 return res;
142 }( );
143 auto last = m_value.end( );
144 std::size_t pos = std::size( m_locs );
145 while( it != last ) {
146 auto name = it.name( );
147 if( name ) {
148 m_locs.emplace_back(
149 daw::string_view( std::data( *name ), std::size( *name ) ), it );
150 } else {
151 m_locs.emplace_back( daw::string_view( ), it );
152 }
153 if( pos == index ) {
154 return pos;
155 }
156 ++pos;
157 ++it;
158 }
159 return std::size( m_locs );
160 }
161
162 public:
165 : m_value( std::move( val ) ) {
166
167 daw_json_assert_weak( ( [&] {
168 auto t = m_value.type( );
169 return ( t == JsonBaseParseTypes::Class ) |
170 ( t == JsonBaseParseTypes::Array );
171 }( ) ),
172 ErrorReason::ExpectedArrayOrClassStart,
173 val.get_raw_state( ) );
174 }
175
178 basic_json_value<PolicyFlags, Allocator>( "{}" ) ) {}
179
180 constexpr basic_stateful_json_value( daw::string_view json_data )
182 basic_json_value<PolicyFlags, Allocator>( json_data ) ) {}
188 m_value = std::move( val );
189 m_locs.clear( );
190 }
191
197 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
198 operator[]( std::string_view key ) {
199 std::size_t pos = move_to( json_member_name( key ) );
200 daw_json_assert_weak( pos < std::size( m_locs ),
201 ErrorReason::UnknownMember );
202 return m_locs[pos].location->value;
203 }
204
210 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
212 std::size_t pos = move_to( member );
213 daw_json_assert_weak( pos < std::size( m_locs ),
214 ErrorReason::UnknownMember );
215 return m_locs[pos].location->value;
216 }
217
223 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
224 at( std::string_view key ) {
225 auto const k = std::string_view( std::data( key ), std::size( key ) );
226 std::size_t pos = move_to( k );
227 if( pos < std::size( m_locs ) ) {
228 return m_locs[pos].location->value;
229 }
230 return { };
231 }
232
238 [[nodiscard]] std::size_t size( ) {
239 JsonBaseParseTypes const current_type = m_value.type( );
240 switch( current_type ) {
241 case JsonBaseParseTypes::Array:
242 case JsonBaseParseTypes::Class:
243 return move_to( ( daw::numeric_limits<std::size_t>::max )( ) );
244 case JsonBaseParseTypes::Number:
245 case JsonBaseParseTypes::Bool:
246 case JsonBaseParseTypes::String:
247 case JsonBaseParseTypes::Null:
248 case JsonBaseParseTypes::None:
249 default:
250 return 0;
251 }
252 }
253
260 [[nodiscard]] std::size_t index_of( std::string_view key ) {
261 auto const k = json_member_name( key );
262 return move_to( k );
263 }
264
270 [[nodiscard]] constexpr bool contains( std::string_view key ) {
271 auto const k = std::string_view( std::data( key ), std::size( key ) );
272 return move_to( k ) < std::size( m_locs );
273 }
274
275 /***
276 * Is the indexed member/element present
277 * This method is O(N) worst case and O(1) if the locations have already
278 * @param index position of member/element
279 * @return true if the member/element is present
280 */
281 [[nodiscard]] constexpr bool contains( std::size_t index ) {
282 return move_to( index ) < size( m_locs );
283 }
284
285 /***
286 * Get the position of the named member
287 * @tparam Integer An integer type
288 * @param index position of member. If negative it returns the position
289 * from one past last, e.g. -1 is last item
290 * @return The name of the member or an empty optional
291 */
292 template<typename Integer>
293 [[nodiscard]] std::optional<std::string_view> name_of( Integer index ) {
294 static_assert( std::is_integral_v<Integer>,
295 "Only integer indices are allowed" );
296 if constexpr( std::is_signed_v<Integer> ) {
297 if( index < 0 ) {
298 index = -index;
299 auto sz = size( );
300 if( static_cast<std::size_t>( index ) >= sz ) {
301 return { };
302 }
303 sz -= static_cast<std::size_t>( index );
304 return std::string_view( std::data( m_locs[sz].name( ) ),
305 std::size( m_locs[sz].name( ) ) );
306 }
307 }
308 std::size_t pos = move_to( static_cast<std::size_t>( index ) );
309 if( pos < std::size( m_locs ) ) {
310 return std::string_view( std::data( m_locs[pos].name( ) ),
311 std::size( m_locs[pos].name( ) ) );
312 }
313 return { };
314 }
315
316 /***
317 * basic_json_value for the indexed member
318 * @tparam Integer An integer type
319 * @param index position of member. If negative it returns the position
320 * from one past last, e.g. -1 is last item
321 * @pre index must exist
322 * @return A new basic_json_value for the indexed member
323 */
324 template<
325 typename Integer DAW_JSON_ENABLEIF( std::is_integral_v<Integer> )>
326 DAW_JSON_REQUIRES( std::is_integral_v<Integer> )
327 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
328 operator[]( Integer index ) {
329 if constexpr( std::is_signed_v<Integer> ) {
330 if( index < 0 ) {
331 index = -index;
332 auto sz = size( );
333 daw_json_assert_weak( ( static_cast<std::size_t>( index ) < sz ),
334 ErrorReason::UnknownMember );
335 sz -= static_cast<std::size_t>( index );
336 return m_locs[sz].location->value;
337 }
338 }
339 std::size_t pos = move_to( static_cast<std::size_t>( index ) );
340 daw_json_assert_weak( pos < std::size( m_locs ),
341 ErrorReason::UnknownMember );
342 return m_locs[pos].location->value;
343 }
344
345 /***
346 * basic_json_value for the indexed member
347 * @tparam Integer An integer type
348 * @param index position of member. If negative it returns the position
349 * from one past last, e.g. -1 is last item
350 * @return A new basic_json_value for the indexed member
351 */
352 template<
353 typename Integer DAW_JSON_ENABLEIF( std::is_integral_v<Integer> )>
354 DAW_JSON_REQUIRES( std::is_integral_v<Integer> )
355 [[nodiscard]] constexpr std::optional<
357 if constexpr( std::is_signed_v<Integer> ) {
358 if( index < 0 ) {
359 index = -index;
360 auto sz = size( );
361 if( static_cast<std::size_t>( index ) >= sz ) {
362 return { };
363 }
364 sz -= static_cast<std::size_t>( index );
365 return m_locs[sz].location->value( );
366 }
367 }
368 std::size_t pos = move_to( static_cast<std::size_t>( index ) );
369 if( pos < std::size( m_locs ) ) {
370 return m_locs[pos].location->value( );
371 }
372 return { };
373 }
374
375 /***
376 * @return A copy of the underlying basic_json_value
377 */
378 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
379 get_json_value( ) const {
380 return m_value;
381 }
382 };
383
385
386 template<json_options_t PolicyFlags, typename Allocator>
389
390 basic_stateful_json_value( daw::string_view )
392
394 } // namespace DAW_JSON_VER
395} // namespace daw::json
constexpr bool contains(std::string_view key)
Is the named member present. This method is O(N) worst case and O(1) if the locations have already.
constexpr basic_json_value< PolicyFlags, Allocator > at(std::string_view key)
Create a basic_json_member for the named member.
std::size_t index_of(std::string_view key)
Return the index of named member. This method is O(N) worst case and O(1) if the locations have alrea...
constexpr basic_json_value< PolicyFlags, Allocator > get_json_value() const
constexpr basic_json_value< PolicyFlags, Allocator > operator[](Integer index)
std::size_t size()
Count the number of elements/members in the JSON class or array This method is O(N) worst case and O(...
constexpr std::optional< basic_json_value< PolicyFlags, Allocator > > at(Integer index)
constexpr basic_json_value< PolicyFlags, Allocator > operator[](json_member_name member)
Create a basic_json_member for the named member.
TryDefaultParsePolicy< BasicParsePolicy< PolicyFlags, Allocator > > ParseState
constexpr basic_stateful_json_value(basic_json_value< PolicyFlags, Allocator > val)
constexpr basic_json_value< PolicyFlags, Allocator > operator[](std::string_view key)
Create a basic_json_member for the named member.
constexpr void reset(basic_json_value< PolicyFlags, Allocator > val)
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
#define DAW_JSON_ENABLEIF(...)
#define DAW_JSON_REQUIRES(...)
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
Customization point traits.
Iterator for iterating over arbitrary JSON members and array elements.
constexpr std::optional< std::string_view > name() const
Name of member.
A non-owning container for arbitrary JSON values that allows movement/iteration through.
constexpr iterator end() const
End of range over class/arrays members/items.
constexpr iterator begin() const
Get the first member/item.
constexpr ParseState get_raw_state() const
Get a copy of the underlying parse state.
constexpr JsonBaseParseTypes type() const
Get the type of JSON value.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20