JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
parse_index.hpp
Go to the documentation of this file.
1/// \file jsonv/parse_index.hpp
2/// Parsed index of a JSON document.
3///
4/// Copyright (c) 2020 by Travis Gockel. All rights reserved.
5///
6/// This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
7/// as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
8/// version.
9///
10/// \author Travis Gockel (travis@gockelhut.com)
11#pragma once
12
13#include <jsonv/config.hpp>
14#include <jsonv/ast.hpp>
15
16#include <optional>
17
18namespace jsonv
19{
20
21class deserialize_options;
22class parse_options;
23
24/// \addtogroup Value
25/// \{
26
27/// Represents the index of a parsed AST. When combined with the original text, can be used to create a \c value. See
28/// \c parse_index::parse to construct instances from JSON source text.
30{
31public:
32 class iterator final
33 {
34 public:
35 using value_type = ast_node;
36
37 public:
38 iterator() = default;
39
40 iterator& operator++();
41 iterator operator++(int)
42 {
43 iterator temp(*this);
44 ++*this;
45 return temp;
46 }
47
48 /// Move to the node after the structure this iterator is on, however much is inside it.
49 ///
50 /// This is a constant-time operation. The index records where each structure ends as it parses the matching
51 /// close token, so stepping over a subtree costs the same whether it holds one element or a million. Use it to
52 /// ignore a value without paying to walk it.
53 ///
54 /// \code
55 /// // `iter` is on the `[` of `"a": [ 1, 2, 3 ]`
56 /// iter.skip_subtree(); // now on the key which follows the array
57 /// \endcode
58 ///
59 /// If the structure was never closed -- only possible when \ref parse_index::success is \c false -- the
60 /// error which truncated the document stands in as its end, so this moves to the end of the index.
61 ///
62 /// \throws std::invalid_argument if this iterator is not on a \c ast_node_type::document_start,
63 /// \c ast_node_type::object_begin or \c ast_node_type::array_begin.
65
67 value_type operator*() const;
68
69 // Note the lack of comparison between `_prefix` -- valid `iterator`s will always have the same `_prefix`
71 bool operator==(const iterator& other) const { return _iter == other._iter; }
73 bool operator!=(const iterator& other) const { return _iter != other._iter; }
75 bool operator< (const iterator& other) const { return _iter < other._iter; }
77 bool operator<=(const iterator& other) const { return _iter <= other._iter; }
79 bool operator> (const iterator& other) const { return _iter > other._iter; }
81 bool operator>=(const iterator& other) const { return _iter >= other._iter; }
82
83 private:
84 explicit iterator(const std::uintptr_t prefix, const std::uint64_t* iter) :
85 _prefix(prefix),
86 _iter(iter)
87 { }
88
89 friend class parse_index;
90
91 private:
92 std::uintptr_t _prefix;
93 const std::uint64_t* _iter;
94 };
95
96 using const_iterator = iterator;
97
98public:
99 /// Creates an empty not-an-AST instance.
100 parse_index() noexcept = default;
101
102 parse_index(parse_index&& src) noexcept :
103 _impl(std::exchange(src._impl, nullptr))
104 { }
105
106 parse_index& operator=(parse_index&& src) noexcept
107 {
108 if (this == &src)
109 return *this;
110
111 using std::swap;
112 swap(_impl, src._impl);
113 src.reset();
114
115 return *this;
116 }
117
118 ~parse_index() noexcept;
119
120 /// \{
121
122 /// Create a \c parse_index from the given \a src JSON.
123 ///
124 /// Parsing is controlled by \a options where they are given, and by \c parse_options::create_default() where they
125 /// are not. The underlying buffer starts with an \a initial_buffer_capacity where one is given; without one, or
126 /// when it is \c nullopt, the buffer is sized according to the length of the \a src string.
127 ///
128 /// \throws std::length_error if a given \a initial_buffer_capacity is too large for the buffer's size in bytes to
129 /// be represented in a \c std::size_t.
131 static parse_index parse(std::string_view src,
132 const parse_options& options,
133 std::optional<std::size_t> initial_buffer_capacity
134 );
136 static parse_index parse(std::string_view src, std::optional<std::size_t> initial_buffer_capacity);
138 static parse_index parse(std::string_view src, const parse_options& options);
140 static parse_index parse(std::string_view src);
141 /// \}
142
143 /// Clear the contents of this instance.
144 void reset();
145
146 /// Check if this instance represents a valid AST. This will be \c false if the source JSON was not valid JSON text.
147 /// This will also be \c false if this instance was default-constructed or moved-from.
148 ///
149 /// \note
150 /// Even if this returns true, it is possible that conversion to a \c jsonv::value will throw an exception. For
151 /// example, if the value of a number exceeds the range of an \c int64_t. This is because JSON does not specify an
152 /// acceptable range for numbers, but the storage of \c jsonv::value does.
154 bool success() const noexcept;
155
156 /// See \ref success.
158 explicit operator bool() const noexcept;
159
160 /// Validate that the parse was a \c success.
161 ///
162 /// \throws parse_error if the parse was not successful. This will contain additional details about why the parse
163 /// failed.
164 /// \throws std::invalid_argument if this instance was default-constructed or moved-from.
165 void validate() const;
166
168 iterator begin() const;
170 iterator cbegin() const { return begin(); }
171
173 iterator end() const;
174
176 iterator cend() const { return end(); }
177
178 /// \{
179
180 /// Build a \c value from the document this index holds. Extraction is controlled by \a options where they are
181 /// given, and by \c deserialize_options::create_default() where they are not.
182 ///
183 /// \throws parse_error if the document holds no value, which is the case for source text that is empty, only
184 /// whitespace or -- with \c parse_options::comments -- only comments. Such an index is a valid one (\c validate
185 /// does not throw for it), but there is nothing to build a \c value from. The error is the input ending
186 /// unexpectedly, at the end of the source text.
191 /// \}
192
193 /// \{
194
195 /// Get a string representation of the AST.
196 ///
197 /// +--------------------+--------+
198 /// | `ast_node_type` | Output |
199 /// +--------------------+--------+
200 /// | `document_start` | `^` |
201 /// | `document_end` | `$` |
202 /// | `object_begin` | `{` |
203 /// | `object_end` | `}` |
204 /// | `array_begin` | `[` |
205 /// | `array_end` | `]` |
206 /// | `string_canonical` | `s` |
207 /// | `string_escaped` | `S` |
208 /// | `key_canonical` | `k` |
209 /// | `key_escaped` | `K` |
210 /// | `literal_true` | `t` |
211 /// | `literal_false` | `f` |
212 /// | `literal_null` | `n` |
213 /// | `integer` | `i` |
214 /// | `decimal` | `d` |
215 /// | `error` | `!` |
216 /// +--------------------+--------+
217 ///
218 /// This exists primarily for debugging purposes.
219 friend std::ostream& operator<<(std::ostream&, const parse_index&);
220 friend std::string to_string(const parse_index&);
221 /// \}
222
223private:
224 struct impl;
225
226 explicit parse_index(impl*) noexcept;
227
228private:
229 impl* _impl = nullptr;
230};
231
232/// \}
233
234}
Utilities for directly dealing with a JSON AST.
Represents an entry in a JSON AST.
Definition ast.hpp:172
Configuration for various deserialization options. This becomes part of the deserialization_context.
iterator & skip_subtree()
Move to the node after the structure this iterator is on, however much is inside it.
Represents the index of a parsed AST.
friend std::string to_string(const parse_index &)
Get a string representation of the AST.
value extract_tree() const
Build a value from the document this index holds.
parse_index() noexcept=default
Creates an empty not-an-AST instance.
friend std::ostream & operator<<(std::ostream &, const parse_index &)
Get a string representation of the AST.
value extract_tree(const deserialize_options &options) const
Build a value from the document this index holds.
Configuration for various parsing options.
Definition parse.hpp:58
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
Definition value.hpp:113
Copyright (c) 2014-2020 by Travis Gockel.
#define JSONV_NODISCARD
Warn if the caller discards the result of this function.
Definition config.hpp:143
#define JSONV_PUBLIC
This function or class is part of the public API for JSON Voorhees.
Definition config.hpp:124
JSONV_PUBLIC void swap(value &a, value &b) noexcept
Swap the values a and b.
STL namespace.
typename detail::optional_type< T >::type optional
Represents a value that may or may not be present.
Definition optional.hpp:239