Coverage Report

Created: 2026-10-10 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_