DAW JSON Link
daw_json_lines_iterator.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 
15 #include "impl/daw_json_value.h"
16 
17 #include <daw/daw_cxmath.h>
18 #include <daw/daw_move.h>
19 #include <daw/daw_scope_guard.h>
20 #include <daw/daw_traits.h>
21 #include <daw/daw_utility.h>
22 
23 #include <array>
24 #include <cstddef>
25 #include <cstdlib>
26 #include <iterator>
27 #include <limits>
28 #include <string>
29 #include <string_view>
30 #include <type_traits>
31 
32 namespace daw::json {
33  inline namespace DAW_JSON_VER {
37  template<typename JsonElement = json_value, auto... PolicyFlags>
40  options::details::make_parse_flags<PolicyFlags...>( ).value>>;
41  using CharT = typename ParseState::CharT;
42 
43  public:
44  using element_type = json_details::json_deduced_type<JsonElement>;
45  static_assert( not std::is_same_v<element_type, void>,
46  "Unknown JsonElement type." );
47  using value_type = json_details::json_result_t<element_type>;
49  using pointer = json_details::arrow_proxy<value_type>;
50  using difference_type = std::ptrdiff_t;
51  // Can do forward iteration and be stored
52  using iterator_category = std::input_iterator_tag;
53 
54  private:
55  ParseState m_state = ParseState( );
56  /***
57  * This lets us fastpath and just skip n characters as we have already
58  * parsed them
59  */
60  mutable CharT *m_can_skip = nullptr;
61 
62  public:
63  explicit json_lines_iterator( ) = default;
64 
65  explicit constexpr json_lines_iterator( daw::string_view json_lines_doc )
66  : m_state( ParseState( std::data( json_lines_doc ),
67  daw::data_end( json_lines_doc ) ) ) {
68 
69  m_state.trim_left( );
70  }
71 
75  [[nodiscard]] constexpr value_type operator*( ) const {
76  daw_json_assert_weak( m_state.has_more( ),
77  ErrorReason::UnexpectedEndOfData, m_state );
78 
79  auto tmp = m_state;
80  auto const run_after_parse = daw::on_scope_exit( [&] {
81  m_can_skip = tmp.first;
82  } );
83  (void)run_after_parse;
84  return json_details::parse_value<element_type, false,
85  element_type::expected_type>( tmp );
86  }
87 
93  [[nodiscard]] constexpr pointer operator->( ) const {
94  return pointer{ operator*( ) };
95  }
96 
99  constexpr json_lines_iterator &operator++( ) {
100  daw_json_assert_weak( m_state.has_more( ),
101  ErrorReason::UnexpectedEndOfData, m_state );
102  if( m_can_skip ) {
103  m_state.first = m_can_skip;
104  m_can_skip = nullptr;
105  } else {
106  (void)json_details::skip_known_value<element_type>( m_state );
107  }
108  m_state.move_next_member_or_end( );
109  return *this;
110  }
111 
113  constexpr void operator++( int ) & {
114  (void)operator++( );
115  }
116 
119  [[nodiscard]] constexpr bool good( ) const {
120  return not m_state.is_null( ) and m_state.has_more( );
121  }
122 
125  [[nodiscard]] explicit constexpr operator bool( ) const {
126  return good( );
127  }
128 
132  [[nodiscard]] constexpr bool
133  operator==( json_lines_iterator const &rhs ) const {
134  if( not( *this ) ) {
135  return not rhs;
136  }
137  if( not rhs ) {
138  return false;
139  }
140  return ( m_state.first == rhs.m_state.first );
141  }
142 
146  [[nodiscard]] constexpr bool
147  operator!=( json_lines_iterator const &rhs ) const {
148  if( not( *this ) ) {
149  return static_cast<bool>( rhs );
150  }
151  if( not rhs ) {
152  return true;
153  }
154  return m_state.first != rhs.m_state.first;
155  }
156 
157  constexpr std::string_view get_raw_json_document( ) const {
158  return std::string_view( m_state.first, m_state.size( ) );
159  }
160  };
162 
166  template<typename JsonElement = json_value, auto... PolicyFlags>
169  options::details::make_parse_flags<PolicyFlags...>( ).value>>;
170  using iterator = json_lines_iterator<JsonElement, PolicyFlags...>;
171  using CharT = typename ParsePolicy::CharT;
172 
173  private:
174  iterator m_first{ };
175  iterator m_last{ };
176 
177  public:
178  explicit json_lines_range( ) = default;
179 
180  explicit constexpr json_lines_range( iterator first,
181  iterator last = iterator( ) )
182  : m_first( first )
183  , m_last( last ) {}
184 
185  explicit constexpr json_lines_range( daw::string_view json_lines_doc )
186  : m_first( json_lines_doc ) {}
187 
189  [[nodiscard]] constexpr iterator begin( ) const {
190  return m_first;
191  }
192 
194  [[nodiscard]] constexpr iterator end( ) const {
195  return m_last;
196  }
197 
200  [[nodiscard]] constexpr bool empty( ) const {
201  return m_first == m_last;
202  }
203  };
204  json_lines_range( daw::string_view ) -> json_lines_range<>;
205 
206  template<typename JsonElement, auto... PolicyFlags>
209  -> json_lines_range<JsonElement, PolicyFlags...>;
210 
214  template<typename JsonElement = json_value, auto... ParsePolicies>
215  std::vector<json_lines_range<JsonElement, ParsePolicies...>>
216  partition_jsonl_document( std::size_t num_partitions,
217  daw::string_view jsonl_doc ) {
218  using result_t =
219  std::vector<json_lines_range<JsonElement, ParsePolicies...>>;
220  if( num_partitions <= 1 ) {
221  return result_t{
222  json_lines_range<JsonElement, ParsePolicies...>( jsonl_doc ) };
223  }
224  auto approx_segsize = jsonl_doc.size( ) / num_partitions;
225  auto result = result_t{ };
226  char const *const last = daw::data_end( jsonl_doc );
227  while( not jsonl_doc.empty( ) ) {
228  char const *tmp = std::data( jsonl_doc ) + approx_segsize;
229  if( tmp >= last ) {
230  result.emplace_back( jsonl_doc );
231  break;
232  }
233  while( tmp < last and *tmp != '\n' ) {
234  ++tmp;
235  }
236  if( tmp < last ) {
237  ++tmp;
238  }
239  auto sz = static_cast<std::size_t>( tmp - std::data( jsonl_doc ) );
240  auto doc = jsonl_doc.pop_front( sz );
241  doc.trim_suffix( );
242  if( not doc.empty( ) ) {
243  result.emplace_back( doc );
244  }
245  }
246  return result;
247  }
248  } // namespace DAW_JSON_VER
249 } // namespace daw::json
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParseState
constexpr bool operator==(json_lines_iterator const &rhs) const
Compare rhs for equivalence.
constexpr bool operator!=(json_lines_iterator const &rhs) const
Check if the other iterator is not equivalent.
#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.
json_lines_range(daw::string_view) -> json_lines_range<>
std::vector< json_lines_range< JsonElement, ParsePolicies... > > partition_jsonl_document(std::size_t num_partitions, daw::string_view jsonl_doc)
parition the jsonl/nbjson document into num_partition non overlapping sub-ranges. This can be used to...
json_lines_iterator(daw::string_view) -> json_lines_iterator<>
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
basic_json_value<> json_value
An untyped JSON value.
Customization point traits.
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParsePolicy
Handles the bounds and policy items for parsing execution and comments.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25