OR-Tools  9.3
strong_integers.h
Go to the documentation of this file.
1// Copyright 2010-2021 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// Generates strongly typed integer types.
15//
16// StrongIndex is a simple template class mechanism for defining "logical"
17// index-like class types that support some of the same functionalities
18// as int, but which prevent assignment, construction, and
19// other operations from other similar integer-like types. Essentially, the
20// template class StrongIndex<StrongIndexName> has the additional
21// property that it cannot be assigned to or constructed from another
22// StrongIndex with a different StrongIndexName.
23//
24// Usage
25// DEFINE_STRONG_INDEX_TYPE(name);
26// where name is the desired (unique) name for the "logical" index type.
27//
28// StrongInt64 is a more general strong integer class based on int64_t.
29// It has the same general type safeness, and supports more integer operators.
30//
31// Usage
32// DEFINE_STRONG_INT64_TYPE(name);
33// where name is the desired (unique) name for the "logical" int64_t type.
34//
35// SUPPORTED OPERATIONS --------------------------------------------------------
36//
37// The StrongIndex type is limited and only supports following operators are
38// supported: unary: ++ (both prefix and postfix), comparison: ==, !=, <, <=, >,
39// >=; assignment: =, +=, -=,; stream: <<. Each operator allows the same
40// StrongIndexName and the int to be used on both left- and right-hand sides.
41//
42// The StrongInt64 type supports all integer operators across StrongInt64
43// with the same StrongIntegerName and int64_t.
44//
45// Both support an accessor value() returning the stored value.
46//
47// The classes also define hash functors that allows the strong types to be used
48// as key to hashable containers.
49
50#ifndef OR_TOOLS_UTIL_STRONG_INTEGERS_H_
51#define OR_TOOLS_UTIL_STRONG_INTEGERS_H_
52
53#include <stddef.h>
54
55#include <cstdint>
56#include <functional>
57#include <iosfwd>
58#include <ostream> // NOLINT
59#include <type_traits>
60
61#include "absl/base/port.h"
62#include "absl/strings/string_view.h"
64#include "ortools/base/macros.h"
65
66namespace operations_research {
67
68// Defines the StrongIndex and typedefs it to index_type_name.
69//
70// Note: The struct index_type_name ## _index_tag_ trickery is needed to ensure
71// that a new type is created per index_type_name.
72#define DEFINE_STRONG_INDEX_TYPE(index_type_name) \
73 struct index_type_name##_index_tag_ { \
74 static constexpr absl::string_view TypeName() { return #index_type_name; } \
75 }; \
76 typedef ::operations_research::StrongIndex<index_type_name##_index_tag_> \
77 index_type_name;
78
79// Defines the StrongInt64 and typedefs it to integer_type_name.
80//
81// Note: The struct integer_type_name ## _integer_tag_ trickery is needed to
82// ensure that a new type is created per integer_type_name.
83#define DEFINE_STRONG_INT64_TYPE(integer_type_name) \
84 struct integer_type_name##_integer_tag_ { \
85 static constexpr absl::string_view TypeName() { \
86 return #integer_type_name; \
87 } \
88 }; \
89 typedef ::operations_research::StrongInt64<integer_type_name##_integer_tag_> \
90 integer_type_name;
91
92// ----------- Implementation ------------
93
94// Note: we need two classes as it is the only way to have different set of
95// operators on each class.
96// Note: We use to class to easily define a different set of operators for the
97// index and int64_t type.
98
99#define STRONG_ASSIGNMENT_OP(StrongClass, IntType, op) \
100 ThisType& operator op(const ThisType& arg_value) { \
101 value_ op arg_value.value(); \
102 return *this; \
103 } \
104 ThisType& operator op(IntType arg_value) { \
105 value_ op arg_value; \
106 return *this; \
107 }
108
109#define INCREMENT_AND_DECREMENT_OPERATORS \
110 ThisType& operator++() { \
111 ++value_; \
112 return *this; \
113 } \
114 const ThisType operator++(int v) { \
115 ThisType temp(*this); \
116 ++value_; \
117 return temp; \
118 } \
119 ThisType& operator--() { \
120 --value_; \
121 return *this; \
122 } \
123 const ThisType operator--(int v) { \
124 ThisType temp(*this); \
125 --value_; \
126 return temp; \
127 }
128
129// Holds an int value and behaves as an int by exposing assignment,
130// unary, comparison, and arithmetic operators.
131//
132// The template parameter StrongIndexName defines the name for the int type and
133// must be unique within a binary (the convenient DEFINE_STRONG_INDEX_TYPE macro
134// at the start of the file generates a unique StrongIndexName).
135//
136// This class is NOT thread-safe.
137template <typename StrongIndexName>
139 public:
140 typedef int ValueType; // Needed for StrongVector.
141 typedef StrongIndex<StrongIndexName> ThisType; // Syntactic sugar.
142
143 static constexpr absl::string_view TypeName() {
144 return StrongIndexName::TypeName();
145 }
146
147 struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher {
148 size_t operator()(const StrongIndex& x) const {
149 return static_cast<size_t>(x.value());
150 }
151 };
152
153 constexpr StrongIndex() : value_(0) {}
154
155 // NOLINTBEGIN(google-explicit-constructor)
156 constexpr StrongIndex(int value) : value_(value) {}
157 // NOLINTEND(google-explicit-constructor)
158
159 StrongIndex& operator=(int arg_value) {
160 value_ = arg_value;
161 return *this;
162 }
163
164 // The class provides a value() accessor returning the stored int value_
165 // as well as a templatized accessor that is just a syntactic sugar for
166 // static_cast<T>(var.value());
167 constexpr int value() const { return value_; }
168
169 template <typename ValType> // Needed for StrongVector.
170 constexpr ValType value() const {
171 return static_cast<ValType>(value_);
172 }
173
174 constexpr const ThisType operator+() const { return ThisType(value_); }
175 constexpr const ThisType operator-() const { return ThisType(-value_); }
176
178
181
182 private:
183 int value_;
184};
185
186// Holds an int64_t value and behaves as an int64_t by exposing assignment,
187// unary, comparison, and arithmetic operators.
188//
189// The template parameter StrongIntegerName defines the name for the int type
190// and must be unique within a binary (the convenient DEFINE_STRONG_INTEGER_TYPE
191// macro at the start of the file generates a unique StrongIntegerName).
192//
193// This class is NOT thread-safe.
194template <typename StrongIntegerName>
196 public:
197 typedef int64_t ValueType; // Needed for StrongVector.
198 typedef StrongInt64<StrongIntegerName> ThisType; // Syntactic sugar.
199
200 static constexpr absl::string_view TypeName() {
201 return StrongIntegerName::TypeName();
202 }
203
204 struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher {
205 size_t operator()(const StrongInt64& x) const {
206 return static_cast<size_t>(x.value());
207 }
208 };
209
210 constexpr StrongInt64() : value_(0) {}
211
212 // NOLINTBEGIN(google-explicit-constructor)
213 constexpr StrongInt64(int64_t value) : value_(value) {}
214 // NOLINTEND(google-explicit-constructor)
215
216 StrongInt64& operator=(int64_t arg_value) {
217 value_ = arg_value;
218 return *this;
219 }
220
221 constexpr int64_t value() const { return value_; }
222
223 template <typename ValType> // Needed for StrongVector.
224 constexpr ValType value() const {
225 return static_cast<ValType>(value_);
226 }
227
229
230 constexpr const ThisType operator+() const { return ThisType(value_); }
231 constexpr const ThisType operator-() const { return ThisType(-value_); }
232 constexpr const ThisType operator~() const { return ThisType(~value_); }
233
241
242 private:
243 int64_t value_;
244};
245
246#undef STRONG_ASSIGNMENT_OP
247#undef INCREMENT_AND_DECREMENT_OPERATORS
248
249// -- NON-MEMBER STREAM OPERATORS ----------------------------------------------
250// We provide the << operator, primarily for logging purposes. Currently, there
251// seems to be no need for an >> operator.
252template <typename StrongIndexName>
253std::ostream& operator<<(std::ostream& os, // NOLINT
255 return os << arg.value();
256}
257
258template <typename StrongIntegerName>
259std::ostream& operator<<(std::ostream& os, // NOLINT
261 return os << arg.value();
262}
263
264// -- NON-MEMBER ARITHMETIC OPERATORS ------------------------------------------
265#define STRONG_TYPE_ARITHMETIC_OP(StrongType, IntType, op) \
266 template <typename StrongName> \
267 constexpr StrongType<StrongName> operator op(StrongType<StrongName> id_1, \
268 StrongType<StrongName> id_2) { \
269 return StrongType<StrongName>(id_1.value() op id_2.value()); \
270 } \
271 template <typename StrongName> \
272 constexpr StrongType<StrongName> operator op(StrongType<StrongName> id, \
273 IntType arg_val) { \
274 return StrongType<StrongName>(id.value() op arg_val); \
275 } \
276 template <typename StrongName> \
277 constexpr StrongType<StrongName> operator op(IntType arg_val, \
278 StrongType<StrongName> id) { \
279 return StrongType<StrongName>(arg_val op id.value()); \
280 }
281
286
294#undef STRONG_TYPE_ARITHMETIC_OP
295
296// -- NON-MEMBER COMPARISON OPERATORS ------------------------------------------
297#define STRONG_TYPE_COMPARISON_OP(StrongType, IntType, op) \
298 template <typename StrongName> \
299 static inline constexpr bool operator op(StrongType<StrongName> id_1, \
300 StrongType<StrongName> id_2) { \
301 return id_1.value() op id_2.value(); \
302 } \
303 template <typename StrongName> \
304 static inline constexpr bool operator op(StrongType<StrongName> id, \
305 IntType val) { \
306 return id.value() op val; \
307 } \
308 template <typename StrongName> \
309 static inline constexpr bool operator op(IntType val, \
310 StrongType<StrongName> id) { \
311 return val op id.value(); \
312 }
313
316STRONG_TYPE_COMPARISON_OP(StrongIndex, int, <); // NOLINT
318STRONG_TYPE_COMPARISON_OP(StrongIndex, int, >); // NOLINT
320
323STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, <); // NOLINT
325STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, >); // NOLINT
327#undef STRONG_TYPE_COMPARISON_OP
328
329// -- ABSL HASHING SUPPORT -----------------------------------------------------
330template <typename StrongIndexName, typename H>
332 return H::combine(std::move(h), i.value());
333}
334
335template <typename StrongIntegerName, typename H>
337 return H::combine(std::move(h), i.value());
338}
339
340} // namespace operations_research
341
342// -- STD HASHING SUPPORT -----------------------------------------------------
343namespace std {
344template <typename Tag>
345struct hash<operations_research::StrongIndex<Tag> >
346 : ::operations_research::StrongIndex<Tag>::Hasher {};
347
348template <typename Tag>
349struct hash<operations_research::StrongInt64<Tag> >
350 : ::operations_research::StrongInt64<Tag>::Hasher {};
351} // namespace std
352
353#endif // OR_TOOLS_UTIL_STRONG_INTEGERS_H_
STRONG_ASSIGNMENT_OP(StrongIndex, int, -=)
struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher
StrongIndex< StrongIndexName > ThisType
constexpr StrongIndex(int value)
constexpr const ThisType operator+() const
STRONG_ASSIGNMENT_OP(StrongIndex, int,+=)
constexpr const ThisType operator-() const
constexpr ValType value() const
StrongIndex & operator=(int arg_value)
static constexpr absl::string_view TypeName()
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t, > >=)
StrongInt64 & operator=(int64_t arg_value)
struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t, *=)
StrongInt64< StrongIntegerName > ThisType
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t,+=)
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t,<<=)
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t,/=)
constexpr const ThisType operator+() const
constexpr const ThisType operator~() const
constexpr const ThisType operator-() const
constexpr ValType value() const
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t, -=)
constexpr int64_t value() const
constexpr StrongInt64(int64_t value)
STRONG_ASSIGNMENT_OP(StrongInt64, int64_t, %=)
static constexpr absl::string_view TypeName()
int64_t hash
Definition: matrix_utils.cc:61
Definition: cleanup.h:22
Collection of objects used to extend the Constraint Solver library.
H AbslHashValue(H h, const StrongIndex< StrongIndexName > &i)
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
STRONG_TYPE_ARITHMETIC_OP(StrongIndex, int,+)
STRONG_TYPE_COMPARISON_OP(StrongIndex, int,==)
STL namespace.
uint64_t Hash(uint64_t num, uint64_t c)
Definition: hash.h:150