/src/s2geometry/src/s2/s2shape_index.cc
Line | Count | Source |
1 | | // Copyright 2012 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // Author: ericv@google.com (Eric Veach) |
17 | | |
18 | | #include "s2/s2shape_index.h" |
19 | | |
20 | | #include <cstdint> |
21 | | #include <limits> |
22 | | |
23 | | #include "absl/base/optimization.h" |
24 | | #include "absl/log/absl_check.h" |
25 | | #include "s2/util/coding/coder.h" |
26 | | #include "s2/util/coding/varint.h" |
27 | | #include "s2/util/gtl/compact_array.h" |
28 | | |
29 | 0 | bool S2ClippedShape::ContainsEdge(int id) const { |
30 | | // Linear search is fast because the number of edges per shape is typically |
31 | | // very small (less than 10). |
32 | 0 | for (int e = 0; e < num_edges(); ++e) { |
33 | 0 | if (edge(e) == id) return true; |
34 | 0 | } |
35 | 0 | return false; |
36 | 0 | } |
37 | | |
38 | 0 | S2ShapeIndexCell::~S2ShapeIndexCell() { |
39 | | // Free memory for all shapes owned by this cell. |
40 | 0 | for (S2ClippedShape& s : shapes_) |
41 | 0 | s.Destruct(); |
42 | 0 | shapes_.clear(); |
43 | 0 | } |
44 | | |
45 | | const S2ClippedShape* |
46 | 0 | S2ShapeIndexCell::find_clipped(int shape_id) const { |
47 | | // Linear search is fine because the number of shapes per cell is typically |
48 | | // very small (most often 1), and is large only for pathological inputs |
49 | | // (e.g. very deeply nested loops). |
50 | 0 | for (const auto& s : shapes_) { |
51 | 0 | if (s.shape_id() == shape_id) return &s; |
52 | 0 | } |
53 | 0 | return nullptr; |
54 | 0 | } |
55 | | |
56 | | // Allocate room for "n" additional clipped shapes in the cell, and return a |
57 | | // pointer to the first new clipped shape. Expects that all new clipped |
58 | | // shapes will have a larger shape id than any current shape, and that shapes |
59 | | // will be added in increasing shape id order. |
60 | 0 | S2ClippedShape* S2ShapeIndexCell::add_shapes(int n) { |
61 | 0 | if (n > 0) { |
62 | 0 | int size = shapes_.size(); |
63 | 0 | shapes_.resize(size + n); |
64 | 0 | return &shapes_[size]; |
65 | 0 | } |
66 | 0 | return nullptr; |
67 | 0 | } |
68 | | |
69 | 0 | void S2ShapeIndexCell::Encode(int num_shape_ids, Encoder* encoder) const { |
70 | | // The encoding is designed to be especially compact in certain common |
71 | | // situations: |
72 | | // |
73 | | // 1. The S2ShapeIndex contains exactly one shape. |
74 | | // |
75 | | // 2. The S2ShapeIndex contains more than one shape, but a particular index |
76 | | // cell contains only one shape (num_clipped == 1). |
77 | | // |
78 | | // 3. The edge ids for a given shape in a cell form a contiguous range. |
79 | | // |
80 | | // The details were optimized by constructing an S2ShapeIndex for each |
81 | | // feature in Google's geographic repository and measuring their total |
82 | | // encoded size. The MutableS2ShapeIndex encoding (of which this function |
83 | | // is just one part) uses an average of 1.88 bytes per vertex for features |
84 | | // consisting of polygons or polylines. |
85 | | // |
86 | | // Note that this code does not bother handling num_shapes >= 2**28 or |
87 | | // num_edges >= 2**29. This could be fixed using varint64 in a few more |
88 | | // places, but if a single cell contains this many shapes or edges then we |
89 | | // have bigger problems than just the encoding format :) |
90 | 0 | if (num_shape_ids == 1) { |
91 | | // If the entire S2ShapeIndex contains just one shape, then we don't need |
92 | | // to encode any shape ids. This is a very important and common case. |
93 | 0 | ABSL_DCHECK_EQ(num_clipped(), 1); // Index invariant: no empty cells. |
94 | 0 | const S2ClippedShape& clipped = this->clipped(0); |
95 | 0 | ABSL_DCHECK_EQ(clipped.shape_id(), 0); |
96 | 0 | int n = clipped.num_edges(); |
97 | 0 | encoder->Ensure(Varint::kMax64 + n * Varint::kMax32); |
98 | 0 | if (n >= 2 && n <= 17 && clipped.edge(n - 1) - clipped.edge(0) == n - 1) { |
99 | | // The cell contains a contiguous range of edges (*most common case*). |
100 | | // If the starting edge id is small then we can encode the cell in one |
101 | | // byte. (The n == 0 and n == 1 cases are encoded compactly below.) |
102 | | // This encoding uses a 1-bit tag because it is by far the most common. |
103 | | // |
104 | | // Encoding: bit 0: 0 |
105 | | // bit 1: contains_center |
106 | | // bits 2-5: (num_edges - 2) |
107 | | // bits 6+: edge_id |
108 | 0 | encoder->put_varint64(static_cast<uint64_t>(clipped.edge(0)) << 6 | |
109 | 0 | (n - 2) << 2 | clipped.contains_center() << 1 | 0); |
110 | 0 | } else if (n == 1) { |
111 | | // The cell contains only one edge. For edge ids up to 15, we can |
112 | | // encode the cell in a single byte. |
113 | | // |
114 | | // Encoding: bits 0-1: 1 |
115 | | // bit 2: contains_center |
116 | | // bits 3+: edge_id |
117 | 0 | encoder->put_varint64(static_cast<uint64_t>(clipped.edge(0)) << 3 | |
118 | 0 | clipped.contains_center() << 2 | 1); |
119 | 0 | } else { |
120 | | // General case (including n == 0, which is encoded compactly here). |
121 | | // |
122 | | // Encoding: bits 0-1: 3 |
123 | | // bit 2: contains_center |
124 | | // bits 3+: num_edges |
125 | 0 | encoder->put_varint64(static_cast<uint64_t>(n) << 3 | |
126 | 0 | clipped.contains_center() << 2 | 3); |
127 | 0 | EncodeEdges(clipped, encoder); |
128 | 0 | } |
129 | 0 | } else { |
130 | 0 | if (num_clipped() > 1) { |
131 | | // The cell contains more than one shape. The tag for this encoding |
132 | | // must be distinguishable from the cases encoded below. We can afford |
133 | | // to use a 3-bit tag because num_clipped is generally small. |
134 | 0 | encoder->Ensure(Varint::kMax32); |
135 | 0 | encoder->put_varint32((num_clipped() << 3) | 3); |
136 | 0 | } |
137 | | // The shape ids are delta-encoded. |
138 | 0 | int shape_id_base = 0; |
139 | 0 | for (int j = 0; j < num_clipped(); ++j) { |
140 | 0 | const S2ClippedShape& clipped = this->clipped(j); |
141 | 0 | ABSL_DCHECK_GE(clipped.shape_id(), shape_id_base); |
142 | 0 | int shape_delta = clipped.shape_id() - shape_id_base; |
143 | 0 | shape_id_base = clipped.shape_id() + 1; |
144 | | |
145 | | // Like the code above except that we also need to encode shape_id(s). |
146 | | // Because of this some choices are slightly different. |
147 | 0 | int n = clipped.num_edges(); |
148 | 0 | encoder->Ensure((n + 2) * Varint::kMax32); |
149 | 0 | if (n >= 1 && n <= 16 && clipped.edge(n - 1) - clipped.edge(0) == n - 1) { |
150 | | // The clipped shape has a contiguous range of up to 16 edges. This |
151 | | // encoding uses a 1-bit tag because it is by far the most common. |
152 | | // |
153 | | // Encoding: bit 0: 0 |
154 | | // bit 1: contains_center |
155 | | // bits 2+: edge_id |
156 | | // Next value: bits 0-3: (num_edges - 1) |
157 | | // bits 4+: shape_delta |
158 | 0 | encoder->put_varint32(clipped.edge(0) << 2 | |
159 | 0 | clipped.contains_center() << 1 | 0); |
160 | 0 | encoder->put_varint32(shape_delta << 4 | (n - 1)); |
161 | 0 | } else if (n == 0) { |
162 | | // Special encoding for clipped shapes with no edges. Such shapes are |
163 | | // common in polygon interiors. This encoding uses a 3-bit tag in |
164 | | // order to leave more bits available for the other encodings. |
165 | | // |
166 | | // NOTE(ericv): When num_clipped > 1, this tag could be 2 bits |
167 | | // (because the tag used to indicate num_clipped > 1 can't appear). |
168 | | // Alternatively, that tag can be considered reserved for future use. |
169 | | // |
170 | | // Encoding: bits 0-2: 7 |
171 | | // bit 3: contains_center |
172 | | // bits 4+: shape_delta |
173 | 0 | encoder->put_varint32(shape_delta << 4 | |
174 | 0 | clipped.contains_center() << 3 | 7); |
175 | 0 | } else { |
176 | | // General case. This encoding uses a 2-bit tag, and the first value |
177 | | // typically is encoded into one byte. |
178 | | // |
179 | | // Encoding: bits 0-1: 1 |
180 | | // bit 2: contains_center |
181 | | // bits 3+: (num_edges - 1) |
182 | | // Next value: shape_delta |
183 | 0 | encoder->put_varint32((n - 1) << 3 | |
184 | 0 | clipped.contains_center() << 2 | 1); |
185 | 0 | encoder->put_varint32(shape_delta); |
186 | 0 | EncodeEdges(clipped, encoder); |
187 | 0 | } |
188 | 0 | } |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | 0 | bool S2ShapeIndexCell::Decode(int num_shape_ids, Decoder* decoder) { |
193 | | // This function inverts the encodings documented above. |
194 | 0 | if (num_shape_ids == 1) { |
195 | | // Entire S2ShapeIndex contains only one shape. |
196 | 0 | S2ClippedShape* clipped = add_shapes(1); |
197 | 0 | uint64_t header = 0; |
198 | 0 | if (!decoder->get_varint64(&header)) return false; |
199 | 0 | if ((header & 1) == 0) { |
200 | | // The cell contains a contiguous range of edges. |
201 | 0 | int num_edges = ((header >> 2) & 15) + 2; |
202 | 0 | clipped->Init(0 /*shape_id*/, num_edges); |
203 | 0 | clipped->set_contains_center((header & 2) != 0); |
204 | | // Edge ids are int32, but we use int64 to guard against overflow. |
205 | 0 | const int64_t edge_id = header >> 6; |
206 | 0 | if (ABSL_PREDICT_FALSE(edge_id + num_edges > |
207 | 0 | std::numeric_limits<int32_t>::max())) { |
208 | 0 | return false; |
209 | 0 | } |
210 | 0 | for (int i = 0; i < num_edges; ++i) { |
211 | | // Range check for `edge_id + i` is performed above. |
212 | 0 | clipped->set_edge(i, static_cast<int>(edge_id + i)); |
213 | 0 | } |
214 | 0 | return true; |
215 | 0 | } |
216 | 0 | if ((header & 2) == 0) { |
217 | | // The cell contains a single edge. |
218 | 0 | clipped->Init(0 /*shape_id*/, 1 /*num_edges*/); |
219 | 0 | clipped->set_contains_center((header & 4) != 0); |
220 | 0 | const int64_t edge_id = header >> 3; |
221 | 0 | if (ABSL_PREDICT_FALSE(edge_id > std::numeric_limits<int32_t>::max())) { |
222 | 0 | return false; |
223 | 0 | } |
224 | 0 | clipped->set_edge(0, edge_id); |
225 | 0 | return true; |
226 | 0 | } |
227 | | // The cell contains some other combination of edges. |
228 | 0 | int num_edges = header >> 3; |
229 | 0 | clipped->Init(0 /*shape_id*/, num_edges); |
230 | 0 | clipped->set_contains_center((header & 4) != 0); |
231 | 0 | return DecodeEdges(num_edges, clipped, decoder); |
232 | 0 | } |
233 | | // S2ShapeIndex contains more than one shape. |
234 | 0 | uint32_t header = 0; |
235 | 0 | if (!decoder->get_varint32(&header)) return false; |
236 | 0 | int num_clipped = 1; |
237 | 0 | if ((header & 7) == 3) { |
238 | | // This cell contains more than one shape. |
239 | 0 | num_clipped = header >> 3; |
240 | 0 | if (!decoder->get_varint32(&header)) return false; |
241 | 0 | } |
242 | 0 | int64_t shape_id = 0; // Shape id is 32-bit, but we guard against overflow. |
243 | 0 | S2ClippedShape* clipped = add_shapes(num_clipped); |
244 | 0 | for (int j = 0; j < num_clipped; ++j, ++clipped, ++shape_id) { |
245 | | // Ensure we don't overflow a 32 bit shape id. |
246 | 0 | if (shape_id >= std::numeric_limits<int>::max()) { |
247 | 0 | return false; |
248 | 0 | } |
249 | | |
250 | 0 | if (j > 0 && !decoder->get_varint32(&header)) return false; |
251 | 0 | if ((header & 1) == 0) { |
252 | | // The clipped shape contains a contiguous range of edges. |
253 | 0 | uint32_t shape_id_count = 0; |
254 | 0 | if (!decoder->get_varint32(&shape_id_count)) return false; |
255 | 0 | shape_id += shape_id_count >> 4; |
256 | 0 | int num_edges = (shape_id_count & 15) + 1; |
257 | 0 | clipped->Init(shape_id, num_edges); |
258 | 0 | clipped->set_contains_center((header & 2) != 0); |
259 | 0 | const int64_t edge_id = header >> 2; |
260 | 0 | if (ABSL_PREDICT_FALSE(edge_id + num_edges > |
261 | 0 | std::numeric_limits<int32_t>::max())) { |
262 | 0 | return false; |
263 | 0 | } |
264 | 0 | for (int i = 0; i < num_edges; ++i) { |
265 | 0 | clipped->set_edge(i, static_cast<int>(edge_id + i)); |
266 | 0 | } |
267 | 0 | } else if ((header & 7) == 7) { |
268 | | // The clipped shape has no edges. |
269 | 0 | shape_id += header >> 4; |
270 | 0 | clipped->Init(shape_id, 0); |
271 | 0 | clipped->set_contains_center((header & 8) != 0); |
272 | 0 | } else { |
273 | | // The clipped shape contains some other combination of edges. |
274 | 0 | if ((header & 3) != 1) { |
275 | 0 | return false; |
276 | 0 | } |
277 | | |
278 | 0 | uint32_t shape_delta = 0; |
279 | 0 | if (!decoder->get_varint32(&shape_delta)) return false; |
280 | 0 | shape_id += shape_delta; |
281 | 0 | int num_edges = (header >> 3) + 1; |
282 | 0 | clipped->Init(shape_id, num_edges); |
283 | 0 | clipped->set_contains_center((header & 4) != 0); |
284 | 0 | if (!DecodeEdges(num_edges, clipped, decoder)) return false; |
285 | 0 | } |
286 | 0 | } |
287 | 0 | return true; |
288 | 0 | } |
289 | | |
290 | | inline void S2ShapeIndexCell::EncodeEdges(const S2ClippedShape& clipped, |
291 | 0 | Encoder* encoder) { |
292 | | // Each entry is an (edge_id, count) pair representing a contiguous range of |
293 | | // edges. The edge ids are delta-encoded such that 0 represents the minimum |
294 | | // valid next edge id. |
295 | | // |
296 | | // Encoding: if bits 0-2 < 7: encodes (count - 1) |
297 | | // - bits 3+: edge delta |
298 | | // if bits 0-2 == 7: |
299 | | // - bits 3+ encode (count - 8) |
300 | | // - Next value is edge delta |
301 | | // |
302 | | // No count is encoded for the last edge (saving 3 bits). |
303 | 0 | int edge_id_base = 0; |
304 | 0 | int num_edges = clipped.num_edges(); |
305 | 0 | for (int i = 0; i < num_edges; ++i) { |
306 | 0 | int edge_id = clipped.edge(i); |
307 | 0 | ABSL_DCHECK_GE(edge_id, edge_id_base); |
308 | 0 | int delta = edge_id - edge_id_base; |
309 | 0 | if (i + 1 == num_edges) { |
310 | | // This is the last edge; no need to encode an edge count. |
311 | 0 | encoder->put_varint32(delta); |
312 | 0 | } else { |
313 | | // Count the edges in this contiguous range. |
314 | 0 | int count = 1; |
315 | 0 | for (; i + 1 < num_edges && clipped.edge(i + 1) == edge_id + count; ++i) { |
316 | 0 | ++count; |
317 | 0 | } |
318 | 0 | if (count < 8) { |
319 | | // Count is encoded in low 3 bits of delta. |
320 | 0 | encoder->put_varint32(delta << 3 | (count - 1)); |
321 | 0 | } else { |
322 | | // Count and delta are encoded separately. |
323 | 0 | encoder->put_varint32((count - 8) << 3 | 7); |
324 | 0 | encoder->put_varint32(delta); |
325 | 0 | } |
326 | 0 | edge_id_base = edge_id + count; |
327 | 0 | } |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | inline bool S2ShapeIndexCell::DecodeEdges(int num_edges, |
332 | | S2ClippedShape* clipped, |
333 | 0 | Decoder* decoder) { |
334 | | // This function inverts the encodings documented above. |
335 | 0 | int64_t edge_id = 0; // Edge id is 32-bit, but we guard against overflow. |
336 | 0 | for (int i = 0; i < num_edges; ) { |
337 | 0 | uint32_t delta = 0; |
338 | 0 | if (!decoder->get_varint32(&delta)) return false; |
339 | 0 | if (i + 1 == num_edges) { |
340 | | // The last edge is encoded without an edge count. |
341 | 0 | edge_id += delta; |
342 | 0 | if (ABSL_PREDICT_FALSE(edge_id > std::numeric_limits<int32_t>::max())) { |
343 | 0 | return false; |
344 | 0 | } |
345 | 0 | clipped->set_edge(i++, edge_id); |
346 | 0 | } else { |
347 | | // Otherwise decode the count and edge delta. |
348 | 0 | uint32_t count = (delta & 7) + 1; |
349 | 0 | delta >>= 3; |
350 | 0 | if (count == 8) { |
351 | 0 | count = delta + 8; |
352 | 0 | if (!decoder->get_varint32(&delta)) return false; |
353 | 0 | } |
354 | | |
355 | | // Guard against overflowing edge memory for bad inputs. |
356 | 0 | if (ABSL_PREDICT_FALSE(i + count > static_cast<uint32_t>(num_edges))) { |
357 | 0 | return false; |
358 | 0 | } |
359 | | |
360 | 0 | edge_id += delta; |
361 | | // Guard against overflowing edge memory for bad inputs. |
362 | 0 | if (ABSL_PREDICT_FALSE(edge_id + count > |
363 | 0 | std::numeric_limits<int32_t>::max())) { |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | for (; count > 0; --count, ++i, ++edge_id) { |
367 | 0 | clipped->set_edge(i, edge_id); |
368 | 0 | } |
369 | 0 | } |
370 | 0 | } |
371 | 0 | return true; |
372 | 0 | } |