Coverage Report

Created: 2025-08-25 06:55

/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_