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;
}
|