OR-Tools  9.6
strong_integers.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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"
63 #include "ortools/base/logging.h"
64 #include "ortools/base/macros.h"
65 
66 namespace 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) { \
115  ThisType temp(*this); \
116  ++value_; \
117  return temp; \
118  } \
119  ThisType& operator--() { \
120  --value_; \
121  return *this; \
122  } \
123  const ThisType operator--(int) { \
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.
137 template <typename StrongIndexName>
138 class StrongIndex {
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  explicit constexpr StrongIndex(int value) : value_(value) {}
156 
157  StrongIndex& operator=(int arg_value) {
158  value_ = arg_value;
159  return *this;
160  }
161 
162  // The class provides a value() accessor returning the stored int value_
163  // as well as a templatized accessor that is just a syntactic sugar for
164  // static_cast<T>(var.value());
165  constexpr int value() const { return value_; }
166 
167  template <typename ValType> // Needed for StrongVector.
168  constexpr ValType value() const {
169  return static_cast<ValType>(value_);
170  }
171 
172  constexpr const ThisType operator+() const { return ThisType(value_); }
173  constexpr const ThisType operator-() const { return ThisType(-value_); }
174 
176 
179 
180  private:
181  int value_;
182 };
183 
184 // Holds an int64_t value and behaves as an int64_t by exposing assignment,
185 // unary, comparison, and arithmetic operators.
186 //
187 // The template parameter StrongIntegerName defines the name for the int type
188 // and must be unique within a binary (the convenient DEFINE_STRONG_INTEGER_TYPE
189 // macro at the start of the file generates a unique StrongIntegerName).
190 //
191 // This class is NOT thread-safe.
192 template <typename StrongIntegerName>
193 class StrongInt64 {
194  public:
195  typedef int64_t ValueType; // Needed for StrongVector.
196  typedef StrongInt64<StrongIntegerName> ThisType; // Syntactic sugar.
197 
198  static constexpr absl::string_view TypeName() {
199  return StrongIntegerName::TypeName();
200  }
201 
202  struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher {
203  size_t operator()(const StrongInt64& x) const {
204  return static_cast<size_t>(x.value());
205  }
206  };
207 
208  constexpr StrongInt64() : value_(0) {}
209 
210  // NOLINTBEGIN(google-explicit-constructor)
211  constexpr StrongInt64(int64_t value) : value_(value) {}
212  // NOLINTEND(google-explicit-constructor)
213 
214  StrongInt64& operator=(int64_t arg_value) {
215  value_ = arg_value;
216  return *this;
217  }
218 
219  constexpr int64_t value() const { return value_; }
220 
221  template <typename ValType> // Needed for StrongVector.
222  constexpr ValType value() const {
223  return static_cast<ValType>(value_);
224  }
225 
227 
228  constexpr const ThisType operator+() const { return ThisType(value_); }
229  constexpr const ThisType operator-() const { return ThisType(-value_); }
230  constexpr const ThisType operator~() const { return ThisType(~value_); }
231 
239 
240  private:
241  int64_t value_;
242 };
243 
244 #undef STRONG_ASSIGNMENT_OP
245 #undef INCREMENT_AND_DECREMENT_OPERATORS
246 
247 // -- NON-MEMBER STREAM OPERATORS ----------------------------------------------
248 // We provide the << operator, primarily for logging purposes. Currently, there
249 // seems to be no need for an >> operator.
250 template <typename StrongIndexName>
251 std::ostream& operator<<(std::ostream& os, // NOLINT
253  return os << arg.value();
254 }
255 
256 template <typename StrongIntegerName>
257 std::ostream& operator<<(std::ostream& os, // NOLINT
259  return os << arg.value();
260 }
261 
262 // -- NON-MEMBER ARITHMETIC OPERATORS ------------------------------------------
263 #define STRONG_TYPE_ARITHMETIC_OP(StrongType, IntType, op) \
264  template <typename StrongName> \
265  constexpr StrongType<StrongName> operator op(StrongType<StrongName> id_1, \
266  StrongType<StrongName> id_2) { \
267  return StrongType<StrongName>(id_1.value() op id_2.value()); \
268  } \
269  template <typename StrongName> \
270  constexpr StrongType<StrongName> operator op(StrongType<StrongName> id, \
271  IntType arg_val) { \
272  return StrongType<StrongName>(id.value() op arg_val); \
273  } \
274  template <typename StrongName> \
275  constexpr StrongType<StrongName> operator op(IntType arg_val, \
276  StrongType<StrongName> id) { \
277  return StrongType<StrongName>(arg_val op id.value()); \
278  }
279 
284 
292 #undef STRONG_TYPE_ARITHMETIC_OP
293 
294 // -- NON-MEMBER COMPARISON OPERATORS ------------------------------------------
295 #define STRONG_TYPE_COMPARISON_OP(StrongType, IntType, op) \
296  template <typename StrongName> \
297  static inline constexpr bool operator op(StrongType<StrongName> id_1, \
298  StrongType<StrongName> id_2) { \
299  return id_1.value() op id_2.value(); \
300  } \
301  template <typename StrongName> \
302  static inline constexpr bool operator op(StrongType<StrongName> id, \
303  IntType val) { \
304  return id.value() op val; \
305  } \
306  template <typename StrongName> \
307  static inline constexpr bool operator op(IntType val, \
308  StrongType<StrongName> id) { \
309  return val op id.value(); \
310  }
311 
314 STRONG_TYPE_COMPARISON_OP(StrongIndex, int, <); // NOLINT
316 STRONG_TYPE_COMPARISON_OP(StrongIndex, int, >); // NOLINT
318 
319 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, ==); // NOLINT
320 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, !=); // NOLINT
321 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, <); // NOLINT
322 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, <=); // NOLINT
323 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, >); // NOLINT
324 STRONG_TYPE_COMPARISON_OP(StrongInt64, int64_t, >=); // NOLINT
325 #undef STRONG_TYPE_COMPARISON_OP
326 
327 // -- ABSL HASHING SUPPORT -----------------------------------------------------
328 template <typename StrongIndexName, typename H>
330  return H::combine(std::move(h), i.value());
331 }
332 
333 template <typename StrongIntegerName, typename H>
335  return H::combine(std::move(h), i.value());
336 }
337 
338 } // namespace operations_research
339 
340 // -- STD HASHING SUPPORT -----------------------------------------------------
341 namespace std {
342 template <typename Tag>
343 struct hash<operations_research::StrongIndex<Tag> >
344  : ::operations_research::StrongIndex<Tag>::Hasher {};
345 
346 template <typename Tag>
347 struct hash<operations_research::StrongInt64<Tag> >
348  : ::operations_research::StrongInt64<Tag>::Hasher {};
349 } // namespace std
350 
351 #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()
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,<<=)
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:63
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,==)
uint64_t Hash(uint64_t num, uint64_t c)
Definition: hash.h:74