/src/s2geometry/src/s2/s2error.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013 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 | | // S2Error is a simple class consisting of an error code and a human-readable |
19 | | // error message. |
20 | | |
21 | | #ifndef S2_S2ERROR_H_ |
22 | | #define S2_S2ERROR_H_ |
23 | | |
24 | | #include <cstdarg> |
25 | | #include <ostream> |
26 | | #include <string> |
27 | | |
28 | | #include "absl/base/attributes.h" |
29 | | #include "absl/status/status.h" |
30 | | #include "absl/strings/str_format.h" |
31 | | #include "absl/strings/string_view.h" |
32 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
33 | | |
34 | | #include "s2/base/port.h" |
35 | | |
36 | | // This class is intended to be copied by value as desired. It uses |
37 | | // the default copy constructor and assignment operator. |
38 | | class S2Error { |
39 | | public: |
40 | | enum Code { |
41 | | OK = 0, // No error. |
42 | | |
43 | | //////////////////////////////////////////////////////////////////// |
44 | | // Generic errors, not specific to geometric objects: |
45 | | |
46 | | UNKNOWN = 1000, // Unknown error. |
47 | | UNIMPLEMENTED = 1001, // Operation is not implemented. |
48 | | OUT_OF_RANGE = 1002, // Argument is out of range. |
49 | | INVALID_ARGUMENT = 1003, // Invalid argument (other than a range error). |
50 | | FAILED_PRECONDITION = 1004, // Object is not in the required state. |
51 | | INTERNAL = 1005, // An internal invariant has failed. |
52 | | DATA_LOSS = 1006, // Data loss or corruption. |
53 | | RESOURCE_EXHAUSTED = 1007, // A resource has been exhausted. |
54 | | CANCELLED = 1008, // Operation was cancelled. |
55 | | |
56 | | //////////////////////////////////////////////////////////////////// |
57 | | // Error codes in the following range can be defined by clients: |
58 | | |
59 | | USER_DEFINED_START = 1000000, |
60 | | USER_DEFINED_END = 9999999, |
61 | | |
62 | | //////////////////////////////////////////////////////////////////// |
63 | | // Errors that apply to more than one type of geometry: |
64 | | |
65 | | NOT_UNIT_LENGTH = 1, // Vertex is not unit length. |
66 | | DUPLICATE_VERTICES = 2, // There are two identical vertices. |
67 | | ANTIPODAL_VERTICES = 3, // There are two antipodal vertices. |
68 | | NOT_CONTINUOUS = 4, // Edges of a chain aren't continuous. |
69 | | INVALID_VERTEX = 5, // Vertex has value that's inf or NaN. |
70 | | |
71 | | //////////////////////////////////////////////////////////////////// |
72 | | // S2Loop errors: |
73 | | |
74 | | LOOP_NOT_ENOUGH_VERTICES = 100, // Loop with fewer than 3 vertices. |
75 | | LOOP_SELF_INTERSECTION = 101, // Loop has a self-intersection. |
76 | | |
77 | | //////////////////////////////////////////////////////////////////// |
78 | | // S2Polygon/S2Shape errors: |
79 | | |
80 | | POLYGON_LOOPS_SHARE_EDGE = 200, // Two polygon loops share an edge. |
81 | | POLYGON_LOOPS_CROSS = 201, // Two polygon loops cross. |
82 | | POLYGON_EMPTY_LOOP = 202, // Polygon has an empty loop. |
83 | | POLYGON_EXCESS_FULL_LOOP = 203, // Non-full polygon has a full loop. |
84 | | |
85 | | // Inconsistent loop orientations were detected, indicating that the |
86 | | // interior is not on the left of all edges. |
87 | | POLYGON_INCONSISTENT_LOOP_ORIENTATIONS = 204, |
88 | | |
89 | | // Loop depths don't correspond to any valid nesting hierarchy. |
90 | | POLYGON_INVALID_LOOP_DEPTH = 205, |
91 | | |
92 | | // Actual polygon nesting does not correspond to the nesting hierarchy |
93 | | // encoded by the loop depths. |
94 | | POLYGON_INVALID_LOOP_NESTING = 206, |
95 | | |
96 | | INVALID_DIMENSION = 207, // Shape dimension isn't valid. |
97 | | SPLIT_INTERIOR = 208, // Interior split by holes. |
98 | | OVERLAPPING_GEOMETRY = 209, // Geometry overlaps where it shouldn't |
99 | | |
100 | | //////////////////////////////////////////////////////////////////// |
101 | | // S2Builder errors: |
102 | | |
103 | | // The S2Builder snap function moved a vertex by more than the specified |
104 | | // snap radius. |
105 | | BUILDER_SNAP_RADIUS_TOO_SMALL = 300, |
106 | | |
107 | | // S2Builder expected all edges to have siblings (as specified by |
108 | | // S2Builder::GraphOptions::SiblingPairs::REQUIRE), but some were missing. |
109 | | BUILDER_MISSING_EXPECTED_SIBLING_EDGES = 301, |
110 | | |
111 | | // S2Builder found an unexpected degenerate edge. For example, |
112 | | // Graph::GetLeftTurnMap() does not support degenerate edges. |
113 | | BUILDER_UNEXPECTED_DEGENERATE_EDGE = 302, |
114 | | |
115 | | // S2Builder found a vertex with (indegree != outdegree), which means |
116 | | // that the given edges cannot be assembled into loops. |
117 | | BUILDER_EDGES_DO_NOT_FORM_LOOPS = 303, |
118 | | |
119 | | // The edges provided to S2Builder cannot be assembled into a polyline. |
120 | | BUILDER_EDGES_DO_NOT_FORM_POLYLINE = 304, |
121 | | |
122 | | // There was an attempt to assemble a polygon from degenerate geometry |
123 | | // without having specified a predicate to decide whether the output is |
124 | | // the empty polygon (containing no points) or the full polygon |
125 | | // (containing all points). |
126 | | BUILDER_IS_FULL_PREDICATE_NOT_SPECIFIED = 305, |
127 | | }; |
128 | | |
129 | | // Creates error with OK status and empty message. |
130 | 0 | S2Error() = default; |
131 | | |
132 | | // Create an error with the specified code and message. |
133 | | // |
134 | | // Note that you can prepend text to an existing error by reinitializeing |
135 | | // like this: |
136 | | // |
137 | | // error = S2Error(error.code(), |
138 | | // absl::StrFormat("Loop %d: %s", j, error.message())); |
139 | 0 | S2Error(Code code, absl::string_view message) : code_(code), text_(message) {} |
140 | | |
141 | 0 | [[nodiscard]] bool ok() const { return code_ == OK; } |
142 | 0 | Code code() const { return code_; } |
143 | 0 | absl::string_view message() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
144 | 0 | return text_; |
145 | 0 | } |
146 | | |
147 | | // Returns a value with an `OK` code. Prefer this to `S2Error()`. |
148 | 0 | static S2Error Ok() { |
149 | | // This will be changed to `return absl::OkStatus();` when we switch over. |
150 | 0 | return S2Error(); |
151 | 0 | } |
152 | | |
153 | 0 | static S2Error Unknown(absl::string_view message) { |
154 | 0 | // This will be changed to `absl::UnknownError()` when we switch over. |
155 | 0 | return S2Error(UNKNOWN, message); |
156 | 0 | } |
157 | | |
158 | 0 | static S2Error Unimplemented(absl::string_view message) { |
159 | 0 | return S2Error(UNIMPLEMENTED, message); |
160 | 0 | } |
161 | | |
162 | 0 | static S2Error OutOfRange(absl::string_view message) { |
163 | 0 | return S2Error(OUT_OF_RANGE, message); |
164 | 0 | } |
165 | | |
166 | 0 | static S2Error InvalidArgument(absl::string_view message) { |
167 | 0 | return S2Error(INVALID_ARGUMENT, message); |
168 | 0 | } |
169 | | |
170 | 0 | static S2Error FailedPrecondition(absl::string_view message) { |
171 | 0 | return S2Error(FAILED_PRECONDITION, message); |
172 | 0 | } |
173 | | |
174 | 0 | static S2Error Internal(absl::string_view message) { |
175 | 0 | return S2Error(INTERNAL, message); |
176 | 0 | } |
177 | | |
178 | 0 | static S2Error DataLoss(absl::string_view message) { |
179 | 0 | return S2Error(DATA_LOSS, message); |
180 | 0 | } |
181 | | |
182 | 0 | static S2Error ResourceExhausted(absl::string_view message) { |
183 | 0 | return S2Error(RESOURCE_EXHAUSTED, message); |
184 | 0 | } |
185 | | |
186 | 0 | static S2Error Cancelled(absl::string_view message) { |
187 | 0 | return S2Error(CANCELLED, message); |
188 | 0 | } |
189 | | |
190 | | private: |
191 | | Code code_ = OK; |
192 | | std::string text_; |
193 | | }; |
194 | | |
195 | | // Converts an absl::Status object into an S2Error. |
196 | | // |
197 | | // absl::Status codes with no exact equivalent in S2Error::Code are converted to |
198 | | // S2Error::UNKNOWN. |
199 | | [[nodiscard]] S2Error ToS2Error(const absl::Status& status); |
200 | | |
201 | | // Converts an S2Error into an absl::Status. |
202 | | // |
203 | | // Custom error space are deprecated, |
204 | | // so S2Error codes with no exact equivalent in absl::StatusCode are converted |
205 | | // as follows: |
206 | | // |
207 | | // - errors related to S2Loop, S2Polygon, and S2Builder, as well as those that |
208 | | // apply to more than one type of geometry are mapped to |
209 | | // absl::StatusCode::kInvalidArgument. |
210 | | // |
211 | | // - client-defined errors (those in the [USER_DEFINED_START,USER_DEFINED_END] |
212 | | // range), UNKNOWN errors, and all other errors not covered above are mapped |
213 | | // to absl::StatusCode::kUnknown |
214 | | // |
215 | | // The above mapping significantly reduces the set of expressible errors. |
216 | | // Clients reacting to specific S2 errors (e.g. polygon validation errors) |
217 | | // should continue to use S2Error for its richer error API. |
218 | | absl::Status ToStatus(const S2Error& error); |
219 | | |
220 | | |
221 | | ////////////////// Implementation details follow //////////////////// |
222 | | |
223 | | |
224 | 0 | inline std::ostream& operator<<(std::ostream& os, const S2Error& error) { |
225 | 0 | return os << error.message(); |
226 | 0 | } |
227 | | |
228 | | #endif // S2_S2ERROR_H_ |