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