summaryrefslogtreecommitdiff
path: root/json-c/src/json_object_iterator.c
blob: 39dbc9b205351a3f071af02720c7d62d6a708b70 (plain)
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
/**
*******************************************************************************
* @file json_object_iterator.c
*
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
*
* 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 <stddef.h>

#include "json.h"
#include "json_object_private.h"

#include "json_object_iterator.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, json_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.
 */

/// Our current representation of the "end" iterator;
///
/// @note May not always be NULL
static const void* kObjectEndIterValue = NULL;

/**
 * ****************************************************************************
 */
struct json_object_iterator
json_object_iter_begin(struct json_object* obj)
{
    struct json_object_iterator iter;
    struct lh_table* pTable;

    /// @note json_object_get_object will return NULL if passed NULL
    ///       or a non-json_type_object instance
    pTable = json_object_get_object(obj);
    JASSERT(NULL != pTable);

    /// @note For a pair-less Object, head is NULL, which matches our
    ///       definition of the "end" iterator
    iter.opaque_ = pTable->head;
    return iter;
}

/**
 * ****************************************************************************
 */
struct json_object_iterator
json_object_iter_end(const struct json_object* obj)
{
    struct json_object_iterator iter;

    JASSERT(NULL != obj);
    JASSERT(json_object_is_type(obj, json_type_object));

    iter.opaque_ = kObjectEndIterValue;

    return iter;
}

/**
 * ****************************************************************************
 */
void
json_object_iter_next(struct json_object_iterator* iter)
{
    JASSERT(NULL != iter);
    JASSERT(kObjectEndIterValue != iter->opaque_);

    iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next;
}


/**
 * ****************************************************************************
 */
const char*
json_object_iter_peek_name(const struct json_object_iterator* iter)
{
    JASSERT(NULL != iter);
    JASSERT(kObjectEndIterValue != iter->opaque_);

    return (const char*)(((struct lh_entry *)iter->opaque_)->k);
}


/**
 * ****************************************************************************
 */
struct json_object*
json_object_iter_peek_value(const struct json_object_iterator* iter)
{
    JASSERT(NULL != iter);
    JASSERT(kObjectEndIterValue != iter->opaque_);

    return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v);
}


/**
 * ****************************************************************************
 */
json_bool
json_object_iter_equal(const struct json_object_iterator* iter1,
                       const struct json_object_iterator* iter2)
{
    JASSERT(NULL != iter1);
    JASSERT(NULL != iter2);

    return (iter1->opaque_ == iter2->opaque_);
}


/**
 * ****************************************************************************
 */
struct json_object_iterator
json_object_iter_init_default(void)
{
    struct json_object_iterator iter;

    /**
     * @note Make this a negative, invalid value, such that
     *       accidental access to it would likely be trapped by the
     *       hardware as an invalid address.
     */
    iter.opaque_ = NULL;

    return iter;
}