Coverage Report

Created: 2025-07-12 06:04

/src/h3/src/h3lib/lib/iterators.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2021 Uber Technologies, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *         http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/** @file IterCellsChildren.c
18
 * @brief Iterator structs and functions for the children of a cell,
19
 * or cells at a given resolution.
20
 */
21
22
#include "iterators.h"
23
24
#include "h3Index.h"
25
26
// extract the `res` digit (0--7) of the current cell
27
0
static int _getResDigit(IterCellsChildren *it, int res) {
28
0
    return H3_GET_INDEX_DIGIT(it->h, res);
29
0
}
30
31
// increment the digit (0--7) at location `res`
32
// H3_PER_DIGIT_OFFSET == 3
33
0
static void _incrementResDigit(IterCellsChildren *it, int res) {
34
0
    H3Index val = 1;
35
0
    val <<= H3_PER_DIGIT_OFFSET * (MAX_H3_RES - res);
36
0
    it->h += val;
37
0
}
38
39
/**
40
 * Create a fully nulled-out child iterator for when an iterator is exhausted.
41
 * This helps minimize the chance that a user will depend on the iterator
42
 * internal state after it's exhausted, like the child resolution, for
43
 * example.
44
 */
45
0
static IterCellsChildren _null_iter(void) {
46
0
    return (IterCellsChildren){
47
0
        .h = H3_NULL, ._parentRes = -1, ._skipDigit = -1};
48
0
}
49
50
/**
51
52
## Logic for iterating through the children of a cell
53
54
We'll describe the logic for ....
55
56
- normal (non pentagon iteration)
57
- pentagon iteration. define "pentagon digit"
58
59
60
### Cell Index Component Diagrams
61
62
The lower 56 bits of an H3 Cell Index describe the following index components:
63
64
- the cell resolution (4 bits)
65
- the base cell number (7 bits)
66
- the child cell digit for each resolution from 1 to 15 (3*15 = 45 bits)
67
68
These are the bits we'll be focused on when iterating through child cells.
69
To help describe the iteration logic, we'll use diagrams displaying the
70
(decimal) values for each component like:
71
72
                            child digit for resolution 2
73
                           /
74
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | ... |
75
|-----|-------------|---|---|---|---|---|---|-----|
76
|   9 |          17 | 5 | 3 | 0 | 6 | 2 | 1 | ... |
77
78
79
### Iteration through children of a hexagon (but not a pentagon)
80
81
Iteration through the children of a *hexagon* (but not a pentagon)
82
simply involves iterating through all the children values (0--6)
83
for each child digit (up to the child's resolution).
84
85
For example, suppose a resolution 3 hexagon index has the following
86
components:
87
                                parent resolution
88
                               /
89
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | ... |
90
|-----|-------------|---|---|---|---|---|---|-----|
91
|   3 |          17 | 3 | 5 | 1 | 7 | 7 | 7 | ... |
92
93
The iteration through all children of resolution 6 would look like:
94
95
96
                                parent res  child res
97
                               /           /
98
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ... |
99
|-----|-------------|---|---|---|---|---|---|---|---|-----|
100
| 6   |          17 | 3 | 5 | 1 | 0 | 0 | 0 | 7 | 7 | ... |
101
| 6   |          17 | 3 | 5 | 1 | 0 | 0 | 1 | 7 | 7 | ... |
102
| ... |             |   |   |   |   |   |   |   |   |     |
103
| 6   |          17 | 3 | 5 | 1 | 0 | 0 | 6 | 7 | 7 | ... |
104
| 6   |          17 | 3 | 5 | 1 | 0 | 1 | 0 | 7 | 7 | ... |
105
| 6   |          17 | 3 | 5 | 1 | 0 | 1 | 1 | 7 | 7 | ... |
106
| ... |             |   |   |   |   |   |   |   |   |     |
107
| 6   |          17 | 3 | 5 | 1 | 6 | 6 | 6 | 7 | 7 | ... |
108
109
110
### Step sequence on a *pentagon* cell
111
112
Pentagon cells have a base cell number (e.g., 97) corresponding to a
113
resolution 0 pentagon, and have all zeros from digit 1 to the digit
114
corresponding to the cell's resolution.
115
(We'll drop the ellipses from now on, knowing that digits should contain
116
7's beyond the cell resolution.)
117
118
                            parent res      child res
119
                           /               /
120
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
121
|-----|-------------|---|---|---|---|---|---|
122
|   6 |          97 | 0 | 0 | 0 | 0 | 0 | 0 |
123
124
Iteration through children of a *pentagon* is almost the same
125
as *hexagon* iteration, except that we skip the *first* 1 value
126
that appears in the "skip digit". This corresponds to the fact
127
that a pentagon only has 6 children, which are denoted with
128
the numbers {0,2,3,4,5,6}.
129
130
The skip digit starts at the child resolution position.
131
When iterating through children more than one resolution below
132
the parent, we move the skip digit to the left
133
(up to the next coarser resolution) each time we skip the 1 value
134
in that digit.
135
136
Iteration would start like:
137
138
                            parent res      child res
139
                           /               /
140
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
141
|-----|-------------|---|---|---|---|---|---|
142
|   6 |          97 | 0 | 0 | 0 | 0 | 0 | 0 |
143
                                           \
144
                                            skip digit
145
146
Noticing we skip the 1 value and move the skip digit,
147
the next iterate would be:
148
149
150
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
151
|-----|-------------|---|---|---|---|---|---|
152
|   6 |          97 | 0 | 0 | 0 | 0 | 0 | 2 |
153
                                       \
154
                                        skip digit
155
156
Iteration continues normally until we get to:
157
158
159
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
160
|-----|-------------|---|---|---|---|---|---|
161
|   6 |          97 | 0 | 0 | 0 | 0 | 0 | 6 |
162
                                       \
163
                                        skip digit
164
165
which is followed by (skipping the 1):
166
167
168
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
169
|-----|-------------|---|---|---|---|---|---|
170
|   6 |          97 | 0 | 0 | 0 | 0 | 2 | 0 |
171
                                   \
172
                                    skip digit
173
174
For the next iterate, we won't skip the `1` in the previous digit
175
because it is no longer the skip digit:
176
177
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
178
|-----|-------------|---|---|---|---|---|---|
179
|   6 |          97 | 0 | 0 | 0 | 0 | 2 | 1 |
180
                                   \
181
                                    skip digit
182
183
Iteration continues normally until we're right before the next skip
184
digit:
185
186
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
187
|-----|-------------|---|---|---|---|---|---|
188
|   6 |          97 | 0 | 0 | 0 | 0 | 6 | 6 |
189
                                   \
190
                                    skip digit
191
192
Which is followed by
193
194
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
195
|-----|-------------|---|---|---|---|---|---|
196
|   6 |          97 | 0 | 0 | 0 | 2 | 0 | 0 |
197
                               \
198
                                skip digit
199
200
and so on.
201
202
 */
203
204
/**
205
 * Initialize a IterCellsChildren struct representing the sequence giving
206
 * the children of cell `h` at resolution `childRes`.
207
 *
208
 * At any point in the iteration, starting once
209
 * the struct is initialized, IterCellsChildren.h gives the current child.
210
 *
211
 * Also, IterCellsChildren.h == H3_NULL when all the children have been iterated
212
 * through, or if the input to `iterInitParent` was invalid.
213
 */
214
0
IterCellsChildren iterInitParent(H3Index h, int childRes) {
215
0
    IterCellsChildren it;
216
0
    _iterInitParent(h, childRes, &it);
217
0
    return it;
218
0
}
219
220
/**
221
 * Internal function - initialize a parent iterator in-place
222
 */
223
0
void _iterInitParent(H3Index h, int childRes, IterCellsChildren *iter) {
224
0
    iter->_parentRes = H3_GET_RESOLUTION(h);
225
226
0
    if (childRes < iter->_parentRes || childRes > MAX_H3_RES || h == H3_NULL) {
227
0
        *iter = _null_iter();
228
0
        return;
229
0
    }
230
231
0
    iter->h = _zeroIndexDigits(h, iter->_parentRes + 1, childRes);
232
0
    H3_SET_RESOLUTION(iter->h, childRes);
233
234
0
    if (H3_EXPORT(isPentagon)(iter->h)) {
235
        // The skip digit skips `1` for pentagons.
236
        // The "_skipDigit" moves to the left as we count up from the
237
        // child resolution to the parent resolution.
238
0
        iter->_skipDigit = childRes;
239
0
    } else {
240
        // if not a pentagon, we can ignore "skip digit" logic
241
0
        iter->_skipDigit = -1;
242
0
    }
243
0
}
244
245
/**
246
 * Step a IterCellsChildren to the next child cell.
247
 * When the iteration is over, IterCellsChildren.h will be H3_NULL.
248
 * Handles iterating through hexagon and pentagon cells.
249
 */
250
0
void iterStepChild(IterCellsChildren *it) {
251
    // once h == H3_NULL, the iterator returns an infinite sequence of H3_NULL
252
0
    if (it->h == H3_NULL) return;
253
254
0
    int childRes = H3_GET_RESOLUTION(it->h);
255
256
0
    _incrementResDigit(it, childRes);
257
258
0
    for (int i = childRes; i >= it->_parentRes; i--) {
259
0
        if (i == it->_parentRes) {
260
            // if we're modifying the parent resolution digit, then we're done
261
0
            *it = _null_iter();
262
0
            return;
263
0
        }
264
265
        // PENTAGON_SKIPPED_DIGIT == 1
266
0
        if (i == it->_skipDigit &&
267
0
            _getResDigit(it, i) == PENTAGON_SKIPPED_DIGIT) {
268
            // Then we are iterating through the children of a pentagon cell.
269
            // All children of a pentagon have the property that the first
270
            // nonzero digit between the parent and child resolutions is
271
            // not 1.
272
            // I.e., we never see a sequence like 00001.
273
            // Thus, we skip the `1` in this digit.
274
0
            _incrementResDigit(it, i);
275
0
            it->_skipDigit -= 1;
276
0
            return;
277
0
        }
278
279
        // INVALID_DIGIT == 7
280
0
        if (_getResDigit(it, i) == INVALID_DIGIT) {
281
0
            _incrementResDigit(
282
0
                it, i);  // zeros out it[i] and increments it[i-1] by 1
283
0
        } else {
284
0
            break;
285
0
        }
286
0
    }
287
0
}
288
289
// create iterator for children of base cell at given resolution
290
0
IterCellsChildren iterInitBaseCellNum(int baseCellNum, int childRes) {
291
0
    if (baseCellNum < 0 || baseCellNum >= NUM_BASE_CELLS || childRes < 0 ||
292
0
        childRes > MAX_H3_RES) {
293
0
        return _null_iter();
294
0
    }
295
296
0
    H3Index baseCell;
297
0
    setH3Index(&baseCell, 0, baseCellNum, 0);
298
299
0
    return iterInitParent(baseCell, childRes);
300
0
}
301
302
// create iterator for all cells at given resolution
303
0
IterCellsResolution iterInitRes(int res) {
304
0
    IterCellsChildren itC = iterInitBaseCellNum(0, res);
305
306
0
    IterCellsResolution itR = {
307
0
        .h = itC.h, ._baseCellNum = 0, ._res = res, ._itC = itC};
308
309
0
    return itR;
310
0
}
311
312
0
void iterStepRes(IterCellsResolution *itR) {
313
    // reached the end of over iterator; emits H3_NULL from now on
314
0
    if (itR->h == H3_NULL) return;
315
316
    // step child iterator
317
0
    iterStepChild(&(itR->_itC));
318
319
    // If the child iterator is exhausted and there are still
320
    // base cells remaining, we initialize the next base cell child iterator
321
0
    if ((itR->_itC.h == H3_NULL) && (itR->_baseCellNum + 1 < NUM_BASE_CELLS)) {
322
0
        itR->_baseCellNum += 1;
323
0
        itR->_itC = iterInitBaseCellNum(itR->_baseCellNum, itR->_res);
324
0
    }
325
326
    // This overall iterator reflects the next cell in the child iterator.
327
    // Note: This sets itR->h = H3_NULL if the base cells were
328
    // exhausted in the check above.
329
0
    itR->h = itR->_itC.h;
330
0
}