Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
enums.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h"
15// IWYU pragma: friend "ortools/math_opt/cpp/.*"
16
17// The MathOpt C++ API defines enums that are used in parameters and results and
18// that corresponds to Proto generated enums.
19//
20// The tools in this header make sure the C++ enums provide the following
21// features:
22// * enumerating all enum values
23// * bidirectional string conversion
24// * operator<< stream support
25// * bidirectional proto generated enum conversion
26//
27// Example declaration:
28//
29// my_file.proto:
30// enum MyEnumProto {
31// MY_ENUM_UNSPECIFIED = 0;
32// MY_ENUM_FIRST_VALUE = 1;
33// MY_ENUM_SECOND_VALUE = 2;
34// }
35//
36// my_file.h:
37// enum class MyEnum {
38// kFirstValue = MY_ENUM_FIRST_VALUE,
39// kSecondValue = MY_ENUM_SECOND_VALUE,
40// };
41//
42// MATH_OPT_DEFINE_ENUM(MyEnum, MY_ENUM_UNSPECIFIED);
43//
44// my_file.cc:
45// std::optional<absl::string_view>
46// Enum<MyEnum>::ToOptString(MyEnum value) {
47// switch (value) {
48// case MyEnum::kFirstValue:
49// return "first_value";
50// case MyEnum::kSecondValue:
51// return "second_value";
52// }
53// return std::nullopt;
54// }
55//
56// absl::Span<const MyEnum> Enum<MyEnum>::AllValues() {
57// static constexpr MyEnum kMyEnumValues[] = {MyEnum::kFirstValue,
58// MyEnum::kSecondValue};
59// return absl::MakeConstSpan(kMyEnumValues);
60// }
61//
62// my_file_test.cc:
63// #include "ortools/math_opt/cpp/enums_testing.h"
64// ...
65// INSTANTIATE_TYPED_TEST_SUITE_P(MyEnum, EnumTest, MyEnum);
66//
67// Once this is done, the following functions are available:
68// * absl::Span<MyEnum> Enum<MyEnum>::AllValues()
69// * optional<MyEnum> EnumFromString<MyEnum>(string_view)
70// * string_view EnumToString(MyEnum)
71// * optional<string_view> EnumToOptString(MyEnum)
72// * optional<MyEnum> EnumFromProto(MyEnumProto)
73// * MyEnumProto EnumToProto(optional<MyEnum>)
74// * MyEnumProto EnumToProto(MyEnum)
75// * operator<<(MyEnum)
76// * operator<<(std::optional<MyEnum>)
77//
78// See examples of usage in the Enum struct documentation below.
79#ifndef OR_TOOLS_MATH_OPT_CPP_ENUMS_H_
80#define OR_TOOLS_MATH_OPT_CPP_ENUMS_H_
81
82#include <optional>
83#include <ostream>
84#include <type_traits>
85
86#include "absl/log/check.h"
87#include "absl/strings/string_view.h"
88#include "absl/types/span.h"
89
91
92// This template is specialized for each enum in the C++ API.
93//
94// It provides a standard way to query properties of those enums and it is used
95// by some global functions below to implement conversion from/to string or
96// proto enum.
97//
98// Usage example:
99//
100// // Iterating on all enum values.
101// for (const auto solver_type : Enum<SolverType>::AllValues()) {
102// ...
103// }
104//
105// // Parsing a flag as an enum.
106// const std::optional<SolverType> solver_type =
107// EnumFromString(absl::GetFlag(FLAGS_solver_type));
108// if (!solver_type) {
109// return util::InvalidArgumentErrorBuilder()
110// _ << "failed to parse --solver_type value: "
111// << absl::GetFlag(FLAGS_solver_type);
112// }
113//
114// // Conversion to string.
115// const SolverType solver_type = ...;
116// LOG(INFO) << "solver: " << solver_type;
117// absl::StrCat(EnumToString(solver_type), "_test");
118// absl::StrCat(EnumToOptString(solver_type).value(), "_test");
119//
120// // Conversion to Proto.
121// const std::optional<SolverType> opt_solver_type = ...;
122// const SolverTypeProto solver_type_proto = EnumToProto(opt_solver_type);
123//
124// // Conversion from Proto.
125// const SolverTypeProto solver_type_proto = ...;
126// const std::optional<SolverType> opt_solver_type =
127// EnumFromProto(solver_type_proto);
128//
129// Implementation note: don't specialize directly and instead use the
130// MATH_OPT_DEFINE_ENUM macro.
131template <typename E>
132struct Enum {
133 // Must be true in all implementation. This is used with std::enable_if to
134 // condition the implementation of some overloads.
135 static constexpr bool kIsImplemented = false;
136
137 // The type of the Proto equivalent to this enum.
138 //
139 // (Here we use int as a placeholder so that the code compiles.)
140 using Proto = int;
141
142 // The value Proto enum that represents the unspecified case.
143 static constexpr Proto kProtoUnspecifiedValue = {};
144
145 // Returns a unique string that represent the enum. Returns nullopt if the
146 // input value is not a valid value of the enum.
147 //
148 // The returned string should not include the enum name and should be in
149 // snake_case (e.g. is the enum is kNoSolutionFound, this should return
150 // "no_solution_found").
151 //
152 // Please prefer using the global functions EnumToString() (or
153 // EnumToOptString() if support for invalid values is needed) instead to
154 // benefit from automatic template type deduction.
155 static std::optional<absl::string_view> ToOptString(E value);
156
157 // Returns all possible values of the enum.
158 static absl::Span<const E> AllValues();
159};
160
161using ProtoEnumIsValid = bool (*)(int);
162
163// This template is specialized for each enum in the Proto API. It
164// defines the correspondence with the C++ enum.
165//
166// Implementation note: don't specialize directly and instead use the
167// MATH_OPT_DEFINE_ENUM macro.
168template <typename P>
169struct EnumProto {
170 // The type of the C++ enum equivalent to the P proto enum.
171 //
172 // (Here we use void as a placeholder so that the code compiles.)
173 using Cpp = void;
174
175 // The smallest valid enum value.
176 static constexpr P kMin = {};
177
178 // The largest valid enum value.
179 static constexpr P kMax = {};
180
181 // Proto function returning the true if the input integer matches a valid
182 // value (some values may be missing in range [kMin, kMax]).
183 static constexpr ProtoEnumIsValid kIsValid = nullptr;
184};
185
186// Returns the Proto enum that matches the input C++ proto, returns
187// Enum<E>::kProtoUnspecifiedValue if the input is std::nullopt.
188template <typename E>
189typename Enum<E>::Proto EnumToProto(std::optional<E> value);
190
191// Returns the Proto enum that matches the input C++ proto.
192//
193// Implementation note: this overload is necessary for EnumToProto(Xxx::kXxx)
194// since C++ won't deduce E in std::optional<E> with the other overload.
195template <typename E>
197
198// Returns the C++ enum that matches the input Proto enum, returns
199// std::nullopt if the input is kProtoUnspecifiedValue.
200template <typename P>
201std::optional<typename EnumProto<P>::Cpp> EnumFromProto(P proto_value);
202
203// Returns a unique string that represent the enum.
204//
205// It CHECKs that the input is a valid enum value. For most users this should
206// always be the case since MathOpt don't generates invalid data.
207//
208// Prefer using operator<< when possible though. As a side benefice it does not
209// CHECK but instead prints the integer value of the invalid input.
210template <typename E>
211absl::string_view EnumToString(E value);
212
213// Returns a unique string that represent the enum. Returns nullopt if the input
214// value is not a valid value of the enum.
215template <typename E>
216std::optional<absl::string_view> EnumToOptString(E value);
217
218// Returns the enum value that corresponds to the input string or nullopt if no
219// enum matches.
220//
221// The expected strings are the one returned by EnumToString().
222//
223// This is O(n) in complexity so use with care.
224template <typename E>
225std::optional<E> EnumFromString(absl::string_view str);
226
227// Overload of operator<< for enum types that implements Enum<E>.
228//
229// It calls EnumToOptString(), printing the returned value if not nullopt. When
230// nullopt it prints the enum numeric value instead.
231template <typename E,
232 // We must use enable_if here to prevent this overload to be selected
233 // for other types than ones that implement Enum<E>.
234 typename = std::enable_if_t<Enum<E>::kIsImplemented>>
235std::ostream& operator<<(std::ostream& out, const E value) {
236 const std::optional<absl::string_view> opt_str = EnumToOptString(value);
237 if (opt_str.has_value()) {
238 out << *opt_str;
239 } else {
240 out << "<invalid enum (" << static_cast<std::underlying_type_t<E>>(value)
241 << ")>";
242 }
243 return out;
244}
245
246// Overload of operator<< for std::optional<E> when Enum<E> is implemented.
247//
248// When the value is nullopt, it prints "<unspecified>", else it prints the enum
249// value.
250template <typename E,
251 // We must use enable_if here to prevent this overload to be selected
252 // for other types than ones that implement Enum<E>.
253 typename = std::enable_if_t<Enum<E>::kIsImplemented>>
254std::ostream& operator<<(std::ostream& out, const std::optional<E> opt_value) {
255 if (opt_value.has_value()) {
256 out << *opt_value;
257 } else {
258 out << "<unspecified>";
259 }
260 return out;
261}
262
264// Template functions implementations after this point.
266
267template <typename E>
268typename Enum<E>::Proto EnumToProto(const std::optional<E> value) {
269 return value ? static_cast<typename Enum<E>::Proto>(*value)
271}
272
273template <typename E>
274typename Enum<E>::Proto EnumToProto(const E value) {
275 return EnumToProto(std::make_optional(value));
277
278template <typename P>
279std::optional<typename EnumProto<P>::Cpp> EnumFromProto(const P proto_value) {
280 if (proto_value == Enum<typename EnumProto<P>::Cpp>::kProtoUnspecifiedValue) {
281 return std::nullopt;
282 }
283 return static_cast<typename EnumProto<P>::Cpp>(proto_value);
284}
285
286template <typename E>
287absl::string_view EnumToString(const E value) {
288 std::optional<absl::string_view> opt_str = Enum<E>::ToOptString(value);
289 CHECK(opt_str.has_value())
290 << "invalid value: " << static_cast<std::underlying_type_t<E>>(value);
291 return *opt_str;
292}
293
294template <typename E>
295std::optional<absl::string_view> EnumToOptString(const E value) {
298
299template <typename E>
300std::optional<E> EnumFromString(const absl::string_view str) {
301 for (const E value : Enum<E>::AllValues()) {
302 if (EnumToOptString(value) == str) {
303 return value;
304 }
305 }
306 return std::nullopt;
307}
308
309// Macros that defines the templates specializations for Enum and EnumProto.
310//
311// The CppEnum parameter is the name of the C++ enum class which values are the
312// Proto enum values. The C++ enum must contain a value for each value of the
313// Proto enum but the UNSPECIFIED one. The proto_unspecified_value is the
314// UNSPECIFIED one.
315//
316// It leaves two functions to be implemented in the .cc file:
317//
318// absl::string_view Enum<CppEnum>::ToOptString(CppEnum value) {
319// absl::Span<const CppEnum> Enum<CppEnum>::AllValues();
320//
321// See the comment at the top of this file for an example. See the comment on
322// Enum struct for the functions that can then be used on enums.
323#define MATH_OPT_DEFINE_ENUM(CppEnum, proto_unspecified_value) \
324 template <> \
325 struct Enum<CppEnum> { \
326 static constexpr bool kIsImplemented = true; \
327 using Proto = CppEnum##Proto; \
328 static constexpr Proto kProtoUnspecifiedValue = proto_unspecified_value; \
329 static std::optional<absl::string_view> ToOptString(CppEnum value); \
330 static absl::Span<const CppEnum> AllValues(); \
331 }; \
332 \
333 template <> \
334 struct EnumProto<CppEnum##Proto> { \
335 using Cpp = CppEnum; \
336 static constexpr CppEnum##Proto kMin = CppEnum##Proto##_MIN; \
337 static constexpr CppEnum##Proto kMax = CppEnum##Proto##_MAX; \
338 static constexpr ProtoEnumIsValid kIsValid = CppEnum##Proto##_IsValid; \
339 } /* missing semicolon to force adding it at the invocation site */
340
341} // namespace operations_research::math_opt
342
343#endif // OR_TOOLS_MATH_OPT_CPP_ENUMS_H_
int64_t value
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
std::optional< absl::string_view > EnumToOptString(E value)
Definition enums.h:297
std::optional< typename EnumProto< P >::Cpp > EnumFromProto(P proto_value)
Definition enums.h:281
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
std::optional< E > EnumFromString(absl::string_view str)
Definition enums.h:302
Enum< E >::Proto EnumToProto(std::optional< E > value)
Definition enums.h:270
absl::string_view EnumToString(E value)
Definition enums.h:289
bool(*)(int) ProtoEnumIsValid
Definition enums.h:161
static constexpr P kMin
The smallest valid enum value.
Definition enums.h:176
static constexpr P kMax
The largest valid enum value.
Definition enums.h:179
static constexpr ProtoEnumIsValid kIsValid
Definition enums.h:183
static constexpr Proto kProtoUnspecifiedValue
The value Proto enum that represents the unspecified case.
Definition enums.h:143
static absl::Span< const E > AllValues()
Returns all possible values of the enum.
static constexpr bool kIsImplemented
Definition enums.h:135
static std::optional< absl::string_view > ToOptString(E value)