4#include <md/object.hpp>
16enum class PathSegmentKind {
24 PathSegmentKind kind = PathSegmentKind::End;
26 std::size_t index = 0;
32inline PathSegment next_segment(
const std::string_view path, std::size_t& pos) {
34 if (pos >= path.size()) {
35 out.kind = PathSegmentKind::End;
39 const char c = path[pos];
43 const std::size_t start = pos;
44 while (pos < path.size() && path[pos] !=
']') {
45 if (path[pos] <
'0' || path[pos] >
'9') {
46 out.kind = PathSegmentKind::Malformed;
51 if (pos >= path.size() || pos == start) {
53 out.kind = PathSegmentKind::Malformed;
57 for (std::size_t i = start; i < pos; ++i) {
58 idx = (idx * 10) +
static_cast<std::size_t
>(path[i] -
'0');
61 out.kind = PathSegmentKind::Index;
70 if (pos >= path.size() || path[pos] ==
'.' || path[pos] ==
'[') {
71 out.kind = PathSegmentKind::Malformed;
74 return next_segment(path, pos);
78 const std::size_t start = pos;
79 while (pos < path.size() && path[pos] !=
'.' && path[pos] !=
'[') {
82 out.kind = PathSegmentKind::Key;
83 out.key = path.substr(start, pos - start);
88inline const Value* walk_path(
const Object& root,
const std::string_view path,
bool& malformed) {
98 PathSegment seg = next_segment(path, pos);
99 if (seg.kind == PathSegmentKind::Malformed) {
103 if (seg.kind != PathSegmentKind::Key) {
109 const Value* cur = root.find_ptr(seg.key);
110 if (cur ==
nullptr) {
115 seg = next_segment(path, pos);
116 if (seg.kind == PathSegmentKind::End) {
119 if (seg.kind == PathSegmentKind::Malformed) {
123 if (seg.kind == PathSegmentKind::Key) {
124 const Object* obj = cur->as_object_if();
125 if (obj ==
nullptr) {
129 cur = obj->find_ptr(seg.key);
130 if (cur ==
nullptr) {
134 const Array* arr = cur->as_array_if();
135 if (arr ==
nullptr) {
139 if (seg.index >= arr->size()) {
142 cur = &(*arr)[seg.index];
147inline Value* walk_path_mut(Object& root,
const std::string_view path,
bool& malformed) {
150 const Object& croot = root;
151 const Value* p = walk_path(croot, path, malformed);
152 return const_cast<Value*
>(p);
158 bool malformed =
false;
159 return detail::walk_path(*
this, path, malformed);
163 bool malformed =
false;
164 return detail::walk_path_mut(*
this, path, malformed);
168 bool malformed =
false;
169 if (
const Value* p = detail::walk_path(*
this, path, malformed); p !=
nullptr) {
173 throw type_error(
"Object::require_path: malformed path or type mismatch: '" +
174 std::string(path) +
"'");
176 throw missing_key_error(
"Object::require_path: not found: '" + std::string(path) +
"'");
180 bool malformed =
false;
181 if (
Value* p = detail::walk_path_mut(*
this, path, malformed); p !=
nullptr) {
185 throw type_error(
"Object::require_path: malformed path or type mismatch: '" +
186 std::string(path) +
"'");
188 throw missing_key_error(
"Object::require_path: not found: '" + std::string(path) +
"'");
192 bool malformed =
false;
193 return detail::walk_path(*
this, path, malformed) !=
nullptr;
Value * find_path(std::string_view path)
Find a value by dotted path (e.g. "a.b[0].c"), or nullptr on miss.
Definition path.hpp:162
bool contains_path(std::string_view path) const
True if path resolves to a value in the object.
Definition path.hpp:191
const Value & require_path(std::string_view path) const
Return the value at path; throws on miss or malformed path.
Definition path.hpp:167
Discriminated union holding one of the JSON-like alternatives (null, bool, signed/unsigned integer,...
Definition value.hpp:67
Thrown when a required key or path is not present in an Object.
Definition error.hpp:14
Thrown when a Value holds a different alternative than the caller demanded.
Definition error.hpp:19