summaryrefslogtreecommitdiff
path: root/src/iterator.cpp
blob: 0362fb149b7fc1566c0411f4525cfd290b6291d5 (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
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
209
210
211
212
/**
 *  IteratorImpl.cpp
 *
 *  Implementation file of the IteratorImpl class
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  @copyright 2014 Copernica BV
 */
#include "includes.h"

/**
 *  Set up namespace
 */
namespace Php {

/**
 *  Iterator destructor method
 *  @param  iter
 *  @param  tsrm_ls
 */
void Iterator::destructor(zend_object_iterator *iter TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;
    
    // delete the iterator
    delete iterator;
    
    // free memory for the meta object
    efree(iter);
}

/**
 *  Iterator valid function
 *  Returns FAILURE or SUCCESS
 *  @param  iter
 *  @param  tsrm_ls
 *  @return int
 */
int Iterator::valid(zend_object_iterator *iter TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;
    
    // check if valid
    return iterator->valid() ? SUCCESS : FAILURE;
}

/**
 *  Fetch the current item
 *  @param  iter
 *  @param  data
 *  @param  tsrm_ls
 */
void Iterator::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;

    // retrieve the value (and store it in a member so that it is not
    // destructed when the function returns)
    iterator->_current = iterator->current();

    // copy the value
    *data = &iterator->_current._val;
}

/**
 *  Fetch the key for the current element (optional, may be NULL). The key
 *  should be written into the provided zval* using the ZVAL_* macros. If
 *  this handler is not provided auto-incrementing integer keys will be
 *  used.
 *  @param  iter
 *  @param  key
 *  @param  tsrm_ls
 */
void Iterator::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;
    
    // retrieve the key
    Value retval(iterator->key());

    // detach the underlying zval
    zval *val = retval.detach();
    
    // copy it to the key
    ZVAL_ZVAL(key, val, 1, 1);
}

/**
 *  Function to retrieve the current key, php 5.3 style
 *  @param  iter
 *  @param  str_key
 *  @param  str_key_len
 *  @param  int_key
 *  @param  tsrm_ls
 *  @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
 */
int Iterator::key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;

    // retrieve the key
    Value retval(iterator->key());
    
    // is this a numeric string?
    if (retval.isString())
    {
        // copy the key and the from the value
        *str_key = estrndup(retval.rawValue(), retval.size());
        *str_key_len = retval.size() + 1;
        
        // done
        return HASH_KEY_IS_STRING;
    }
    else
    {
        // convert to a numeric
        *int_key = retval.numericValue();
        
        // done
        return HASH_KEY_IS_LONG;
    }
}

/**
 *  Step forwards to the next element
 *  @param  iter
 *  @param  tsrm_ls
 */
void Iterator::next(zend_object_iterator *iter TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;

    // call the next method
    iterator->next();
}

/**
 *  Rewind the iterator back to the start
 *  @param  iter
 *  @param  tsrm_ls
 */
void Iterator::rewind(zend_object_iterator *iter TSRMLS_DC)
{
    // get the actual iterator
    Iterator *iterator = (Iterator *)iter->data;
    
    // call the rewind method
    iterator->rewind();
}

/**
 *  Get access to all iterator functions
 *  @return zend_object_iterator_funcs
 */
zend_object_iterator_funcs *Iterator::functions()
{
    // static variable with all functions
    static zend_object_iterator_funcs funcs;
    
    // static variable that knows if the funcs are already initialized
    static bool initialized = false;
    
    // no need to set anything if already initialized
    if (initialized) return &funcs;
    
    // set the members
    funcs.dtor = &Iterator::destructor;
    funcs.valid = &Iterator::valid;
    funcs.get_current_data = &Iterator::current;
    funcs.get_current_key = &Iterator::key;
    funcs.move_forward = &Iterator::next;
    funcs.rewind = &Iterator::rewind;
    
    // invalidate is not yet supported
    funcs.invalidate_current = nullptr;
    
    // remember that functions are initialized
    initialized = true;
    
    // done
    return &funcs;
}

/**
 *  Internal method that returns the implementation object
 *  @return zend_object_iterator
 */
struct _zend_object_iterator *Iterator::implementation()
{
    // create an iterator
    zend_object_iterator *iterator = (zend_object_iterator *)emalloc(sizeof(zend_object_iterator));
    
    // initialize all properties
    iterator->data = this;
    iterator->index = 0;
    iterator->funcs = functions();

    // done
    return iterator;
}

/**
 *  End namespace
 */
}