25 [[nodiscard]]
constexpr std::string string()
const noexcept
30 [[nodiscard]]
constexpr bool is_singular()
const noexcept
37 [[nodiscard]]
constexpr std::string string()
const noexcept
42 [[nodiscard]]
constexpr bool is_singular()
const noexcept
49 [[nodiscard]]
constexpr std::string string()
const noexcept
54 [[nodiscard]]
constexpr bool is_singular()
const noexcept
61 [[nodiscard]]
constexpr std::string string()
const noexcept
66 [[nodiscard]]
constexpr bool is_singular()
const noexcept
73 constexpr names(
names const&)
noexcept =
default;
75 constexpr names& operator=(
names const&)
noexcept =
default;
76 constexpr names& operator=(
names&&)
noexcept =
default;
77 constexpr names()
noexcept =
default;
84 [[nodiscard]]
constexpr std::string string()
const noexcept
88 for (
auto const& name : *
this) {
102 [[nodiscard]]
constexpr bool is_singular()
const noexcept
113 constexpr indices()
noexcept =
default;
115 [[nodiscard]]
constexpr std::string string()
const noexcept
119 for (
auto const index : *
this) {
124 r += hi::to_string(index);
131 [[nodiscard]] generator<std::size_t> filter(
std::size_t size)
const noexcept
133 auto const size_ = narrow_cast<ptrdiff_t>(size);
135 for (
auto const index : *
this) {
136 auto const index_ = index >= 0 ? index : size_ + index;
137 if (index_ >= 0 and index_ < size_) {
138 co_yield narrow_cast<std::size_t>(index_);
143 [[nodiscard]]
constexpr bool is_singular()
const noexcept
154 constexpr slice(
slice const&)
noexcept =
default;
156 constexpr slice& operator=(
slice const&)
noexcept =
default;
157 constexpr slice& operator=(
slice&&)
noexcept =
default;
159 constexpr slice(ptrdiff_t first, ptrdiff_t last, ptrdiff_t step) noexcept : first(first), last(last), step(step) {}
161 [[nodiscard]]
constexpr bool last_is_empty()
const noexcept
173 auto const size_ = narrow_cast<ptrdiff_t>(size);
174 auto const begin = first >= 0 ? first : size_ + first;
175 return narrow_cast<std::size_t>(std::clamp(
begin, 0_z, size_));
188 if (last_is_empty()) {
192 auto const size_ = narrow_cast<ptrdiff_t>(size);
193 auto const end = last >= 0 ? last : size_ + last;
194 auto const last_ = std::clamp(
end, 0_z, size_);
196 auto const first_ =
begin(size);
197 auto const distance = last_ - first_;
198 auto const steps = distance / step;
199 return narrow_cast<std::size_t>(first_ + steps * step);
203 [[nodiscard]]
constexpr std::string string() const noexcept
205 if (last_is_empty()) {
206 return std::format(
"[{}:e:{}]", first, step);
208 return std::format(
"[{}:{}:{}]", first, last, step);
212 [[nodiscard]]
constexpr bool is_singular() const noexcept
218 using node = std::variant<root, current, wildcard, descend, names, indices, slice>;
220 using value_type =
typename container_type::value_type;
221 using iterator =
typename container_type::iterator;
222 using const_iterator =
typename container_type::const_iterator;
224 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
225 [[nodiscard]]
constexpr jsonpath(It it, ItEnd last) : _nodes()
227 auto lexer_it = lexer<lexer_config::json_style()>.parse(it, last);
228 auto token_it = make_lookahead_iterator<4>(lexer_it);
230 while (token_it != std::default_sentinel) {
231 if (*token_it ==
'.') {
232 _nodes.
emplace_back(parse_child_operator(++token_it, std::default_sentinel));
234 }
else if (*token_it ==
'[') {
235 _nodes.
emplace_back(parse_indexing_operator(++token_it, std::default_sentinel));
237 }
else if (*token_it ==
'$') {
238 hi_check(_nodes.
empty(),
"Root node '$' not at start of path.");
242 }
else if (*token_it ==
'@') {
243 hi_check(_nodes.
empty(),
"Current node '@' not at start of path.");
247 }
else if (*token_it == token::id) {
248 hi_check(_nodes.
empty(),
"Unexpected child name {}.", *token_it);
253 throw parse_error(std::format(
"Unexpected token {}.", *token_it));
258 [[nodiscard]]
constexpr jsonpath(std::string_view rhs) : jsonpath(rhs.begin(), rhs.end()) {}
260 [[nodiscard]]
constexpr bool empty() const noexcept
262 return _nodes.
empty();
270 for (
auto const& node : _nodes) {
272 [](
auto const& node_) {
273 return node_.is_singular();
280 [[nodiscard]]
constexpr std::size_t size() const noexcept
282 return _nodes.
size();
285 [[nodiscard]]
constexpr iterator begin() noexcept
287 return _nodes.
begin();
290 [[nodiscard]]
constexpr const_iterator begin() const noexcept
292 return _nodes.
begin();
295 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
300 [[nodiscard]]
constexpr iterator end() noexcept
305 [[nodiscard]]
constexpr const_iterator end() const noexcept
310 [[nodiscard]]
constexpr const_iterator cend() const noexcept
312 return _nodes.
cend();
315 [[nodiscard]]
constexpr friend std::string to_string(jsonpath
const& path)
noexcept
318 for (
auto const& node : path._nodes) {
320 [](
auto const& node_) {
321 return node_.string();
331 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
332 [[nodiscard]]
constexpr static node parse_slicing_operator(It& it, ItEnd last)
338 if (it.size() >= 2 and it[0] ==
'-' and it[1] == token::integer) {
339 auto tmp =
static_cast<size_t>(it[1]);
340 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Start-index out of range {}", tmp);
341 start = -narrow_cast<ptrdiff_t>(tmp);
344 }
else if (*it == token::integer) {
345 auto tmp =
static_cast<size_t>(*it);
346 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Start-index out of range {}", tmp);
347 start = narrow_cast<ptrdiff_t>(tmp);
350 }
else if (*it ==
':') {
354 throw parse_error(std::format(
"Unexpected token while parsing start-index of the slicing operator, got {}", *it));
357 hi_check(it != last,
"Unexpected end-of-text after the start-index of the slicing operator.");
358 hi_check(*it ==
':',
"Expecting ':' adter the start-index of the slicing operator, got {}", *it);
361 hi_check(it != last,
"Unexpected end-of-text while parsing the end-index of the slicing operator.");
364 return slice{start, end, step};
366 }
else if (it.size() >= 2 and it[0] ==
'-' and it[1] == token::integer) {
367 auto tmp =
static_cast<size_t>(it[1]);
368 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"End-index out of range {}", tmp);
369 end = -narrow_cast<ptrdiff_t>(tmp);
372 }
else if (*it == token::integer) {
373 auto tmp =
static_cast<size_t>(*it);
374 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"End-index out of range {}", tmp);
375 end = narrow_cast<ptrdiff_t>(tmp);
378 }
else if (*it ==
':' or *it ==
']') {
382 throw parse_error(std::format(
"Unexpected token while parsing the end-index of the slicing operator, got {}", *it));
385 hi_check(it != last,
"Unexpected end-of-text after the end-index of the slicing operator.");
388 return slice{start, end, step};
390 }
else if (it.size() >= 2 and it[0] ==
'-' and it[1] == token::integer) {
391 auto tmp =
static_cast<size_t>(it[1]);
392 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Step-value out of range {}", tmp);
393 step = -narrow_cast<ptrdiff_t>(tmp);
396 }
else if (*it == token::integer) {
397 auto tmp =
static_cast<size_t>(*it);
398 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Step-value out of range {}", tmp);
399 step = narrow_cast<ptrdiff_t>(tmp);
403 throw parse_error(std::format(
"Unexpected token while parsing step-value of the slicing operator, got {}", *it));
406 hi_check(it != last,
"Unexpected end-of-text after the step-value of the slicing operator.");
407 hi_check(*it ==
']',
"Expecting '] after step-value of the slicing operator, got {}", *it);
409 return slice{start, end, step};
412 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
413 [[nodiscard]]
constexpr static node parse_integer_indexing_operator(It& it, ItEnd last)
418 if (it.size() >= 2 and it[0] ==
'-' and it[1] == token::integer) {
419 auto tmp =
static_cast<size_t>(it[1]);
420 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Index out of range {}", tmp);
421 r.push_back(-narrow_cast<ptrdiff_t>(tmp));
424 }
else if (*it == token::integer) {
425 auto tmp =
static_cast<size_t>(*it);
426 hi_check(can_narrow_cast<ptrdiff_t>(tmp),
"Index out of range {}", tmp);
427 r.push_back(narrow_cast<ptrdiff_t>(tmp));
431 throw parse_error(std::format(
"Expected an integer-index, got {}", *it));
435 throw parse_error(
"Unexpected end-of-text while parsing the index operator '['.");
437 }
else if (*it ==
']') {
441 }
else if (*it ==
',') {
446 throw parse_error(std::format(
"Unexpected token after a integer-index: {}.", *it));
451 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
452 [[nodiscard]]
constexpr static node parse_name_indexing_operator(It& it, ItEnd last)
457 if (*it != token::id and *it != token::sstr and *it != token::dstr) {
458 throw parse_error(std::format(
"Expected a name-index, got {}", *it));
464 throw parse_error(
"Unexpected end-of-text while parsing the index operator '['.");
466 }
else if (*it ==
']') {
470 }
else if (*it ==
',') {
475 throw parse_error(std::format(
"Unexpected token after a name-index: {}.", *it));
480 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
481 [[nodiscard]]
constexpr static node parse_indexing_operator(It& it, ItEnd last)
483 hi_check(it != last,
"Unexpected end-of-text at index operator token '['.");
486 hi_check(it.size() >= 2 and it[1] ==
']',
"Expected end of wildcast-indexing operator '[*', got {}.", it[1]);
491 *it ==
':' or (it.size() >= 2 and it[0] == token::integer and it[1] ==
':') or
492 (it.size() >= 3 and it[0] ==
'-' and it[1] == token::integer and it[2] ==
':')) {
493 return parse_slicing_operator(it, last);
495 }
else if (*it == token::integer or (it.size() >= 2 and it[0] ==
'-' and it[1] == token::integer)) {
496 return parse_integer_indexing_operator(it, last);
498 }
else if (*it == token::id or *it == token::sstr or *it == token::dstr) {
499 return parse_name_indexing_operator(it, last);
503 std::format(
"Expected a integer index or name-index after indexing operator '[', got token {}.", *it));
507 template<std::input_iterator It, std::sentinel_for<It> ItEnd>
508 [[nodiscard]]
constexpr static node parse_child_operator(It& it, ItEnd last)
510 hi_check(it != last,
"Unexpected end-of-text at child operator token '.'.");
516 }
else if (*it ==
'.') {
517 if (it.size() >= 2 and it[1] ==
'[') {
530 }
else if (*it == token::id) {
536 throw parse_error(std::format(
"Expected a child name or wildcard, got token {}.", *it));