Skip to content

Commit 7843fbd

Browse files
committed
as noted in CHANGES.md
1 parent 2d1dd64 commit 7843fbd

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## New Features
44

5+
- Add an iterator for `JsonObject` to support range-for loops
6+
- Add `find()` to `JsonValue` to find a sub-value based on a path e.g "top/[4]/next"
57
- Add method `native_value()` to `JsonValue` which can be used for object tracing and debugging.
68

79
## Bug Fixes

library/include/json/Json.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class JsonValue : public api::ExecutionContext {
128128
return m_value;
129129
}
130130

131+
JsonValue find(const var::StringView path, const char* delimiter = "/") const;
132+
133+
131134
protected:
132135
struct Key {
133136
Key(const var::StringView value)
@@ -146,6 +149,7 @@ class JsonValue : public api::ExecutionContext {
146149

147150
private:
148151
friend class JsonDocument;
152+
friend class JsonObjectIterator;
149153
friend class JsonObject;
150154
friend class JsonArray;
151155
friend class JsonTrue;
@@ -200,13 +204,58 @@ template <class Derived> class JsonKeyValueList : public var::Vector<Derived> {
200204
}
201205
};
202206

207+
class JsonObjectIterator : private JsonApi {
208+
public:
209+
210+
JsonObjectIterator() = default;
211+
212+
JsonObjectIterator(json_t * value){
213+
m_json_value = value;
214+
m_json_iter = api()->object_iter(m_json_value);
215+
}
216+
217+
218+
bool operator!=(JsonObjectIterator const &a) const noexcept {
219+
return m_json_iter != a.m_json_iter;
220+
}
221+
222+
JsonObject operator*() const noexcept;
223+
224+
JsonObjectIterator &operator++() {
225+
m_json_iter = api()->object_iter_next(m_json_value, m_json_iter);
226+
return *this;
227+
}
228+
229+
230+
private:
231+
json_t * m_json_value = nullptr;
232+
void * m_json_iter = nullptr;
233+
};
234+
203235
class JsonObject : public JsonValue {
204236
public:
205237
JsonObject();
206238

207239
JsonObject(const JsonObject &value);
208240
JsonObject &operator=(const JsonObject &value);
209241

242+
243+
JsonObjectIterator begin() const noexcept {
244+
return JsonObjectIterator(m_value);
245+
}
246+
247+
JsonObjectIterator end() const noexcept {
248+
return JsonObjectIterator(nullptr);
249+
}
250+
251+
JsonObjectIterator cbegin() const noexcept {
252+
return JsonObjectIterator(m_value);
253+
}
254+
255+
JsonObjectIterator cend() const noexcept {
256+
return JsonObjectIterator(nullptr);
257+
}
258+
210259
template <class T> JsonKeyValueList<T> construct_key_list() {
211260
KeyList list = get_key_list();
212261
JsonKeyValueList<T> result;

library/src/Json.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ const JsonObject &JsonValue::to_object() const {
192192
return static_cast<const JsonObject &>(*this);
193193
}
194194

195+
JsonObject JsonObjectIterator::operator*() const noexcept {
196+
return JsonValue(m_json_value)
197+
.to_object()
198+
.at(api()->object_iter_key(m_json_iter));
199+
}
200+
195201
JsonObject &JsonValue::to_object() { return static_cast<JsonObject &>(*this); }
196202

197203
const JsonArray &JsonValue::to_array() const {
@@ -487,6 +493,82 @@ JsonValue JsonObject::at(const var::StringView key) const {
487493
return JsonValue(api()->object_get(m_value, Key(key).cstring));
488494
}
489495

496+
JsonValue
497+
JsonValue::find(const var::StringView path, const char *delimiter) const {
498+
const auto list = path.split(delimiter);
499+
JsonValue current = *this;
500+
501+
auto get_offset_from_string = [](var::StringView item) {
502+
return item.pop_back().pop_back().to_unsigned_long();
503+
};
504+
505+
for (const auto item : list) {
506+
if (item.is_empty()) {
507+
API_RETURN_VALUE_ASSIGN_ERROR(JsonValue(), "empty item provided", EINVAL);
508+
return JsonValue();
509+
}
510+
511+
if (current.is_object()) {
512+
auto next = current.to_object().at(item);
513+
if (next.is_valid()) {
514+
current = next;
515+
continue;
516+
}
517+
518+
if (item.at(0) == '{') {
519+
const auto object_offset = get_offset_from_string(item);
520+
size_t count = 0;
521+
bool is_found = false;
522+
for (const auto &value : current.to_object()) {
523+
if (count == object_offset) {
524+
current = value;
525+
is_found = true;
526+
break;
527+
}
528+
count++;
529+
}
530+
if (!is_found) {
531+
API_RETURN_VALUE_ASSIGN_ERROR(
532+
JsonValue(),
533+
"didn't find {} offset",
534+
EINVAL);
535+
}
536+
} else {
537+
current = current.to_object().at(item);
538+
}
539+
} else if (current.is_array()) {
540+
if (item.at(0) == '[') {
541+
if (current.is_array() == false) {
542+
API_RETURN_VALUE_ASSIGN_ERROR(JsonValue(), "not an array", EINVAL);
543+
}
544+
const auto array_offset = get_offset_from_string(item);
545+
;
546+
if (current.to_array().count() <= array_offset) {
547+
API_RETURN_VALUE_ASSIGN_ERROR(
548+
JsonValue(),
549+
"[] is beyond array",
550+
EINVAL);
551+
}
552+
current = current.to_array().at(array_offset);
553+
} else {
554+
API_RETURN_VALUE_ASSIGN_ERROR(
555+
JsonValue(),
556+
"array not specified []",
557+
EINVAL);
558+
return JsonValue();
559+
}
560+
}
561+
if( current.is_valid() == false ){
562+
API_RETURN_VALUE_ASSIGN_ERROR(
563+
JsonValue(),
564+
"invalid path",
565+
EINVAL);
566+
return JsonValue();
567+
}
568+
}
569+
return current;
570+
}
571+
490572
JsonArray::JsonArray() { m_value = JsonArray::create(); }
491573

492574
JsonArray::JsonArray(const JsonArray &value) { add_reference(value.m_value); }

0 commit comments

Comments
 (0)