-
Notifications
You must be signed in to change notification settings - Fork 32
/
json_object_iterator.c
208 lines (187 loc) · 5.44 KB
/
json_object_iterator.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/**
*******************************************************************************
* @file fjson_object_iterator.c
*
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
* @brief json-c forces clients to use its private data
* structures for JSON Object iteration. This API
* implementation corrects that by abstracting the
* private json-c details.
*
*******************************************************************************
*/
#include "config.h"
#include <stddef.h>
#include "json.h"
#include "json_object_private.h"
#include "json_object_iterator.h"
#include "debug.h"
/**
* How It Works
*
* For each JSON Object, json-c maintains a linked list of zero
* or more lh_entry (link-hash entry) structures inside the
* Object's link-hash table (lh_table).
*
* Each lh_entry structure on the JSON Object's linked list
* represents a single name/value pair. The "next" field of the
* last lh_entry in the list is set to NULL, which terminates
* the list.
*
* We represent a valid iterator that refers to an actual
* name/value pair via a pointer to the pair's lh_entry
* structure set as the iterator's opaque_ field.
*
* We follow json-c's current pair list representation by
* representing a valid "end" iterator (one that refers past the
* last pair) with a NULL value in the iterator's opaque_ field.
*
* A JSON Object without any pairs in it will have the "head"
* field of its lh_table structure set to NULL. For such an
* object, fjson_object_iter_begin will return an iterator with
* the opaque_ field set to NULL, which is equivalent to the
* "end" iterator.
*
* When iterating, we simply update the iterator's opaque_ field
* to point to the next lh_entry structure in the linked list.
* opaque_ will become NULL once we iterate past the last pair
* in the list, which makes the iterator equivalent to the "end"
* iterator.
*/
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_begin(struct fjson_object *const __restrict__ obj)
{
struct fjson_object_iterator iter = {
.objs_remain = 0,
.curr_idx = 0,
.pg = NULL
};
if(obj->o_type == fjson_type_object) {
iter.objs_remain = obj->o.c_obj.nelem;
if(iter.objs_remain > 0) {
iter.curr_idx = 0;
iter.pg = &obj->o.c_obj.pg;
/* check if first slot is empty, if so, advance */
if(iter.pg->children[0].k == NULL) {
++iter.objs_remain; /* correct _iter_next decrement */
fjson_object_iter_next(&iter);
}
}
}
return iter;
}
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_end(const struct fjson_object __attribute__((unused)) *obj)
{
struct fjson_object_iterator iter = {
.objs_remain = 0,
.curr_idx = 0,
.pg = NULL
};
return iter;
}
/**
* ****************************************************************************
*/
void
fjson_object_iter_next(struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
if(iter->objs_remain > 0) {
--iter->objs_remain;
if(iter->objs_remain > 0) {
++iter->curr_idx;
if(iter->curr_idx == FJSON_OBJECT_CHLD_PG_SIZE) {
iter->pg = iter->pg->next;
iter->curr_idx = 0;
}
/* check empty slots; TODO: recurse or iterate? */
if(iter->pg->children[iter->curr_idx].k == NULL) {
++iter->objs_remain; /* correct */
fjson_object_iter_next(iter);
}
}
}
}
/**
* ****************************************************************************
*/
const char*
fjson_object_iter_peek_name(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return iter->pg->children[iter->curr_idx].k;
}
/**
* ****************************************************************************
*/
struct fjson_object*
fjson_object_iter_peek_value(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return iter->pg->children[iter->curr_idx].v;
}
/**
* ****************************************************************************
*/
struct _fjson_child*
_fjson_object_iter_peek_child(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return (struct _fjson_child*) &(iter->pg->children[iter->curr_idx]);
}
/**
* ****************************************************************************
*/
fjson_bool
fjson_object_iter_equal(const struct fjson_object_iterator* iter1,
const struct fjson_object_iterator* iter2)
{
int is_eq;
JASSERT(NULL != iter1);
JASSERT(NULL != iter2);
if (iter1->objs_remain == iter2->objs_remain) {
if (iter1->objs_remain == 0) {
is_eq = 1;
} else {
if ( (iter1->curr_idx == iter2->curr_idx) &&
(iter1->pg == iter2->pg) ) {
is_eq = 1;
} else {
is_eq = 0;
}
}
} else {
is_eq= 0;
}
return is_eq;
}
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_init_default(void)
{
struct fjson_object_iterator iter;
/**
* @note Make this an invalid value, such that
* accidental access to it would likely be trapped by the
* hardware as an invalid address.
*/
iter.pg = NULL;
iter.curr_idx = 0;
iter.objs_remain = 1;
return iter;
}