Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
strong_int.h
Go to the documentation of this file.
1// Copyright 2010-2025 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// StrongInt<T> is a simple template class mechanism for defining "logical"
15// integer-like class types that support almost all of the same functionality
16// as native integer types, but which prevents assignment, construction, and
17// other operations from other integer-like types. In other words, you cannot
18// assign from raw integer types or other StrongInt<> types, nor can you do
19// most arithmetic or logical operations. This provides a simple form of
20// dimensionality in that you can add two instances of StrongInt<T>, producing
21// a StrongInt<T>, but you can not add a StrongInt<T> and a raw T nor can you
22// add a StrongInt<T> and a StrongInt<U>. Generally an arithmetic operator is
23// defined here if and only if its mathematical result would be a quantity with
24// the same dimension. Details on supported operations are below.
25//
26// In addition to type strength, StrongInt provides a way to inject (optional)
27// validation of the various operations. This allows you to define StrongInt
28// types that check for overflow conditions and react in standard or custom
29// ways.
30//
31// A StrongInt<T> with a NullStrongIntValidator should compile away to a raw T
32// in optimized mode. What this means is that the generated assembly for:
33//
34// int64_t foo = 123;
35// int64_t bar = 456;
36// int64_t baz = foo + bar;
37// constexpr int64_t fubar = 789;
38//
39// ...should be identical to the generated assembly for:
40//
41// DEFINE_STRONG_INT_TYPE(MyStrongInt, int64_t);
42// MyStrongInt foo(123);
43// MyStrongInt bar(456);
44// MyStrongInt baz = foo + bar;
45// constexpr MyStrongInt fubar(789);
46//
47// Since the methods are all inline and non-virtual and the class has just
48// one data member, the compiler can erase the StrongInt class entirely in its
49// code-generation phase. This also means that you can pass StrongInt<T>
50// around by value just as you would a raw T.
51//
52// It is important to note that StrongInt does NOT generate compile time
53// warnings or errors for overflows on implicit constant conversions.
54// For example, the below demonstrates a case where the 2 are not equivalent
55// at compile time and can lead to subtle initialization bugs:
56//
57// DEFINE_STRONG_INT_TYPE(MyStrongInt8, int8_t);
58// int8_t foo = 1024; // Compile error: const conversion to ...
59// MyStrongInt8 foo(1024); // Compiles ok: foo has undefined / 0 value.
60//
61// Usage:
62// DEFINE_STRONG_INT_TYPE(Name, NativeType);
63//
64// Defines a new StrongInt type named 'Name' in the current namespace with
65// no validation of operations.
66//
67// Name: The desired name for the new StrongInt typedef. Must be unique
68// within the current namespace.
69// NativeType: The primitive integral type this StrongInt will hold, as
70// defined by std::numeric_limits::is_integer (see <type_traits>).
71//
72// StrongInt<TagType, NativeType, ValidatorType = NullStrongIntValidator>
73//
74// Creates a new StrongInt instance directly.
75//
76// TagType: The unique type which discriminates this StrongInt<T> from
77// other StrongInt<U> types.
78// NativeType: The primitive integral type this StrongInt will hold, as
79// defined by std::numeric_limits::is_integer (see <type_traits>).
80// ValidatorType: The type of validation used by this StrongInt type. A
81// few pre-built validator types are provided here, but the caller can
82// define any custom validator they desire.
83//
84// Supported operations:
85// StrongInt<T> = StrongInt<T>
86// !StrongInt<T> => bool
87// ~StrongInt<T> => StrongInt<T>
88// -StrongInt<T> => StrongInt<T>
89// +StrongInt<T> => StrongInt<T>
90// ++StrongInt<T> => StrongInt<T>
91// StrongInt<T>++ => StrongInt<T>
92// --StrongInt<T> => StrongInt<T>
93// StrongInt<T>-- => StrongInt<T>
94// StrongInt<T> + StrongInt<T> => StrongInt<T>
95// StrongInt<T> - StrongInt<T> => StrongInt<T>
96// StrongInt<T> * (numeric type) => StrongInt<T>
97// StrongInt<T> / (numeric type) => StrongInt<T>
98// StrongInt<T> % (numeric type) => StrongInt<T>
99// StrongInt<T> << (numeric type) => StrongInt<T>
100// StrongInt<T> >> (numeric type) => StrongInt<T>
101// StrongInt<T> & StrongInt<T> => StrongInt<T>
102// StrongInt<T> | StrongInt<T> => StrongInt<T>
103// StrongInt<T> ^ StrongInt<T> => StrongInt<T>
104//
105// For binary operations, the equivalent op-equal (eg += vs. +) operations are
106// also supported. Other operator combinations should cause compile-time
107// errors.
108//
109// This class also provides a .value() accessor method and defines a hash
110// functor that allows the IntType to be used as key to hashable containers.
111//
112// This class can be streamed to LOG(), and printed using absl::StrCat(),
113// absl::Substitute(), and absl::StrFormat(). Use the "%v" format specifier
114// with absl::StrFormat().
115//
116// Validators:
117// NullStrongIntValidator: Do no validation. This should be entirely
118// optimized away by the compiler.
119
120#ifndef OR_TOOLS_BASE_STRONG_INT_H_
121#define OR_TOOLS_BASE_STRONG_INT_H_
122
123#include <cstddef>
124#include <cstdint>
125#include <functional>
126#include <iosfwd>
127#include <iterator>
128#include <limits>
129#include <ostream>
130#include <string>
131#include <type_traits>
132#include <utility>
133
134#include "absl/meta/type_traits.h"
135#include "absl/strings/numbers.h"
136#include "absl/strings/str_cat.h"
137#include "absl/strings/str_format.h"
138#include "absl/strings/string_view.h"
139#include "absl/strings/substitute.h"
140
141namespace util_intops {
142
143// Define the validators which can be plugged-in to make StrongInt resilient to
144// things like overflows. This is a do-nothing implementation of the
145// compile-time interface.
146//
147// NOTE: For all validation functions that operate on an existing StrongInt<T>,
148// the type argument 'T' *must* be StrongInt<T>::ValueType (the int type being
149// strengthened).
150struct NullStrongIntValidator {
151 // Note that this templated default implementation has an arbitrary bool
152 // return value for the sole purpose of conforming to c++11 constexpr.
153 //
154 // Custom validator implementations can choose to return void or use a similar
155 // return value constexpr construct if constexpr initialization is desirable.
156 //
157 // The StrongInt class does not care about or use the returned value. Any
158 // returned value is solely there to allow the constexpr declaration; custom
159 // validators can only fail / abort when detecting an invalid value.
160 //
161 // For example, other than the constexpr behavior, the below 2 custom
162 // validator implementations are logically equivalent:
163 //
164 // template<typename T, typename U>
165 // static void ValidateInit(U arg) {
166 // if (arg < 0) LOG(FATAL) << "arg < 0";
167 // }
168 //
169 // template<typename T, typename U>
170 // static constexpr bool ValidateInit(U arg) {
171 // return (arg < 0) ? (LOG(FATAL) << "arg < 0", false) : false;
172 // }
173 //
174 // A constexpr implementation has the added advantage that the validation can
175 // take place (fail) at compile time.
176
177 // Verify initialization of StrongInt<T> from arg, type U.
178 template <typename T, typename U>
179 static constexpr bool ValidateInit(U /*arg*/) {
180 return true;
181 }
182 // Verify -value.
183 template <typename T>
184 static constexpr bool ValidateNegate(T /*value*/) {
185 return true;
186 }
187 // Verify ~value;
188 template <typename T>
189 static constexpr bool ValidateBitNot(T /*value*/) {
190 return true;
191 }
192 // Verify lhs + rhs.
193 template <typename T>
194 static constexpr bool ValidateAdd(T /*lhs*/, T /*rhs*/) {
195 return true;
196 }
197 // Verify lhs - rhs.
198 template <typename T>
199 static constexpr bool ValidateSubtract(T /*lhs*/, T /*rhs*/) {
200 return true;
201 }
202 // Verify lhs * rhs.
203 template <typename T, typename U>
204 static constexpr bool ValidateMultiply(T /*lhs*/, U /*rhs*/) {
205 return true;
206 }
207 // Verify lhs / rhs.
208 template <typename T, typename U>
209 static constexpr bool ValidateDivide(T /*lhs*/, U /*rhs*/) {
210 return true;
211 }
212 // Verify lhs % rhs.
213 template <typename T, typename U>
214 static constexpr bool ValidateModulo(T /*lhs*/, U /*rhs*/) {
215 return true;
216 }
217 // Verify lhs << rhs.
218 template <typename T>
219 static constexpr bool ValidateLeftShift(T /*lhs*/, int64_t /*rhs*/) {
220 return true;
221 }
222 // Verify lhs >> rhs.
223 template <typename T>
224 static constexpr bool ValidateRightShift(T /*lhs*/, int64_t /*rhs*/) {
225 return true;
226 }
227 // Verify lhs & rhs.
228 template <typename T>
229 static constexpr bool ValidateBitAnd(T /*lhs*/, T /*rhs*/) {
230 return true;
231 }
232 // Verify lhs | rhs.
233 template <typename T>
234 static constexpr bool ValidateBitOr(T /*lhs*/, T /*rhs*/) {
235 return true;
236 }
237 // Verify lhs ^ rhs.
238 template <typename T>
239 static constexpr bool ValidateBitXor(T /*lhs*/, T /*rhs*/) {
240 return true;
241 }
242};
243
244template <typename TagType, typename NativeType,
245 typename ValidatorType = NullStrongIntValidator>
246class StrongInt;
247
248// Type trait for detecting if a type T is a StrongInt type.
249template <typename T>
250struct IsStrongInt : public std::false_type {};
251
252template <typename... Ts>
253struct IsStrongInt<StrongInt<Ts...>> : public std::true_type {};
254
255// C++17-style helper variable template.
256template <typename T>
257inline constexpr bool IsStrongIntV = IsStrongInt<T>::value;
258
259// Holds a google3-supported integer value (of type NativeType) and behaves as
260// a NativeType by exposing assignment, unary, comparison, and arithmetic
261// operators.
262//
263// This class is NOT thread-safe.
264template <typename TagType, typename NativeType, typename ValidatorType>
265class StrongInt {
266 public:
267 typedef NativeType ValueType;
268
269 struct Hasher {
270 size_t operator()(const StrongInt& x) const {
271 return static_cast<size_t>(x.value());
272 }
273 };
274
275 static constexpr absl::string_view TypeName() { return TagType::TypeName(); }
276
277 // Default value initialization.
278 constexpr StrongInt()
279 : value_((ValidatorType::template ValidateInit<ValueType>(NativeType()),
280 NativeType())) {}
281
282 // Explicit initialization from another StrongInt type that has an
283 // implementation of:
284 //
285 // ToType StrongIntConvert(FromType source, ToType*);
286 //
287 // This uses Argument Dependent Lookup (ADL) to find which function to
288 // call.
289 //
290 // Example: Assume you have two StrongInt types.
291 //
292 // DEFINE_STRONG_INT_TYPE(Bytes, int64_t);
293 // DEFINE_STRONG_INT_TYPE(Megabytes, int64_t);
294 //
295 // If you want to be able to (explicitly) construct an instance of Bytes from
296 // an instance of Megabytes, simply define a converter function in the same
297 // namespace as either Bytes or Megabytes (or both):
298 //
299 // Megabytes StrongIntConvert(Bytes arg, Megabytes* /* unused */) {
300 // return Megabytes((arg >> 20).value());
301 // };
302 //
303 // The second argument is needed to differentiate conversions, and it always
304 // passed as NULL.
305 template <typename ArgTagType, typename ArgNativeType,
306 typename ArgValidatorType>
307 explicit constexpr StrongInt(
308 StrongInt<ArgTagType, ArgNativeType, ArgValidatorType> arg)
309 // We have to pass both the "from" type and the "to" type as args for the
310 // conversions to be differentiated. The converter can not be a template
311 // because explicit template call syntax defeats ADL.
312 : value_(
313 StrongIntConvert(arg, static_cast<StrongInt*>(nullptr)).value()) {}
314
315 // Explicit initialization from a numeric primitive.
316 template <
317 class T,
318 class = std::enable_if_t<std::is_same_v<
319 decltype(static_cast<ValueType>(std::declval<T>())), ValueType>>>
320 explicit constexpr StrongInt(T init_value)
321 : value_((ValidatorType::template ValidateInit<ValueType>(init_value),
322 static_cast<ValueType>(init_value))) {}
323
324 // Use the default copy constructor, assignment, and destructor.
325
326 // Accesses the raw value.
327 constexpr ValueType value() const { return value_; }
328
329 // Accesses the raw value, with cast.
330 // Primarily for compatibility with int-type.h
331 template <typename ValType>
332 constexpr ValType value() const {
333 return static_cast<ValType>(value_);
334 }
335
336 // Explicitly cast the raw value only if the underlying value is convertible
337 // to T.
338 template <typename T,
339 typename = absl::enable_if_t<absl::conjunction<
340 std::bool_constant<std::numeric_limits<T>::is_integer>,
341 std::is_convertible<ValueType, T>>::value>>
342 constexpr explicit operator T() const {
343 return value_;
344 }
345
346 // Metadata functions.
347 static constexpr StrongInt Max() {
348 return StrongInt(std::numeric_limits<ValueType>::max());
349 }
350 static constexpr StrongInt Min() {
351 return StrongInt(std::numeric_limits<ValueType>::min());
352 }
353
354 // Unary operators.
355 bool operator!() const { return value_ == 0; }
356 StrongInt operator+() const { return StrongInt(value_); }
357 StrongInt operator-() const {
358 ValidatorType::template ValidateNegate<ValueType>(value_);
359 return StrongInt(-value_);
360 }
361 StrongInt operator~() const {
362 ValidatorType::template ValidateBitNot<ValueType>(value_);
363 return StrongInt(ValueType(~value_));
364 }
365
366 // Increment and decrement operators.
367 StrongInt& operator++() { // ++x
368 ValidatorType::template ValidateAdd<ValueType>(value_, ValueType(1));
369 ++value_;
370 return *this;
371 }
372 StrongInt operator++(int /*postfix_flag*/) { // x++
373 ValidatorType::template ValidateAdd<ValueType>(value_, ValueType(1));
374 StrongInt temp(*this);
375 ++value_;
376 return temp;
377 }
378 StrongInt& operator--() { // --x
379 ValidatorType::template ValidateSubtract<ValueType>(value_, ValueType(1));
380 --value_;
381 return *this;
382 }
383 StrongInt operator--(int /*postfix_flag*/) { // x--
384 ValidatorType::template ValidateSubtract<ValueType>(value_, ValueType(1));
385 StrongInt temp(*this);
386 --value_;
387 return temp;
388 }
389
390 // Action-Assignment operators.
391 StrongInt& operator+=(StrongInt arg) {
392 ValidatorType::template ValidateAdd<ValueType>(value_, arg.value());
393 value_ += arg.value();
394 return *this;
395 }
396 StrongInt& operator-=(StrongInt arg) {
397 ValidatorType::template ValidateSubtract<ValueType>(value_, arg.value());
398 value_ -= arg.value();
399 return *this;
400 }
401 template <typename ArgType,
402 std::enable_if_t<!IsStrongIntV<ArgType>>* = nullptr>
403 StrongInt& operator*=(ArgType arg) {
404 ValidatorType::template ValidateMultiply<ValueType, ArgType>(value_, arg);
405 value_ *= arg;
406 return *this;
407 }
408 template <typename ArgType,
409 std::enable_if_t<!IsStrongIntV<ArgType>>* = nullptr>
410 StrongInt& operator/=(ArgType arg) {
411 ValidatorType::template ValidateDivide<ValueType, ArgType>(value_, arg);
412 value_ /= arg;
413 return *this;
414 }
415 template <typename ArgType,
416 std::enable_if_t<!IsStrongIntV<ArgType>>* = nullptr>
417 StrongInt& operator%=(ArgType arg) {
418 ValidatorType::template ValidateModulo<ValueType, ArgType>(value_, arg);
419 value_ %= arg;
420 return *this;
421 }
422 StrongInt& operator<<=(int64_t arg) { // NOLINT(whitespace/operators)
423 ValidatorType::template ValidateLeftShift<ValueType>(value_, arg);
424 value_ <<= arg;
425 return *this;
426 }
427 StrongInt& operator>>=(int64_t arg) { // NOLINT(whitespace/operators)
428 ValidatorType::template ValidateRightShift<ValueType>(value_, arg);
429 value_ >>= arg;
430 return *this;
431 }
432 StrongInt& operator&=(StrongInt arg) {
433 ValidatorType::template ValidateBitAnd<ValueType>(value_, arg.value());
434 value_ &= arg.value();
435 return *this;
436 }
437 StrongInt& operator|=(StrongInt arg) {
438 ValidatorType::template ValidateBitOr<ValueType>(value_, arg.value());
439 value_ |= arg.value();
440 return *this;
441 }
442 StrongInt& operator^=(StrongInt arg) {
443 ValidatorType::template ValidateBitXor<ValueType>(value_, arg.value());
444 value_ ^= arg.value();
445 return *this;
446 }
447
448 template <typename H>
449 friend H AbslHashValue(H h, const StrongInt& i) {
450 return H::combine(std::move(h), i.value_);
451 }
452
453 private:
454 // The integer value of type ValueType.
455 ValueType value_;
456
457 static_assert(std::numeric_limits<ValueType>::is_integer,
458 "invalid integer type for strong int");
459};
460
461// Define AbslStringify, for logging, absl::StrCat, and absl::StrFormat.
462// Abseil logging prefers using AbslStringify over operator<<.
463//
464// When using StrongInt with absl::StrFormat, use the "%v" specifier.
465//
466// Note: The user is also able to provide a custom AbslStringify. Example:
467//
468// DEFINE_STRONG_INT_TYPE(MyStrongInt, int64_t);
469//
470// template <typename Sink>
471// void AbslStringify(Sink &sink, MyStrongInt arg) { ... }
472template <typename Sink, typename... T>
473void AbslStringify(Sink& sink, StrongInt<T...> arg) {
474 using ValueType = typename decltype(arg)::ValueType;
475
476 // int8_t/uint8_t are not supported by the "%v" specifier due to it being
477 // ambiguous whether an integer or character should be printed.
478 if constexpr (std::is_same_v<ValueType, int8_t>) {
479 absl::Format(&sink, "%d", arg.value());
480 } else if constexpr (std::is_same_v<ValueType, uint8_t>) {
481 absl::Format(&sink, "%u", arg.value());
482 } else {
483 absl::Format(&sink, "%v", arg.value());
484 }
485}
486
487template <typename TagType, typename ValueType>
488static std::string IntParseError(absl::string_view text) {
489 return absl::Substitute("'$0' is not a valid $1 [min: $2, max: $3]", text,
490 TagType::TypeName(),
491 std::numeric_limits<ValueType>::min(),
492 std::numeric_limits<ValueType>::max());
493}
494
495// Allows typed strings to be used as ABSL_FLAG values.
496template <typename TagType, typename ValueType, typename ValidatorType>
497bool AbslParseFlag(absl::string_view text,
498 StrongInt<TagType, ValueType, ValidatorType>* out,
499 std::string* error) {
500 ValueType value;
501 if constexpr (sizeof(ValueType) >= 4) {
502 if (!absl::SimpleAtoi(text, &value)) {
503 *error = IntParseError<TagType, ValueType>(text);
504 return false;
505 }
506 } else {
507 // Why doesn't absl::SimpleAtoi support smaller int types?
508 int32_t larger_value;
509 if (!absl::SimpleAtoi(text, &larger_value) ||
510 larger_value > std::numeric_limits<ValueType>::max() ||
511 larger_value < std::numeric_limits<ValueType>::min()) {
512 *error = IntParseError<TagType, ValueType>(text);
513 return false;
514 }
515
516 value = static_cast<ValueType>(larger_value);
517 }
518
519 *out = StrongInt<TagType, ValueType, ValidatorType>(value);
520 return true;
521}
522
523template <typename TagType, typename ValueType, typename ValidatorType>
524std::string AbslUnparseFlag(
525 const StrongInt<TagType, ValueType, ValidatorType>& val) {
526 return absl::StrCat(val.value());
527}
528
529// Provide the << operator, primarily for logging purposes.
530template <typename TagType, typename ValueType, typename ValidatorType>
531std::ostream& operator<<(std::ostream& os,
532 StrongInt<TagType, ValueType, ValidatorType> arg) {
533 return os << arg.value();
534}
535
536// Provide the << operator, primarily for logging purposes. Specialized for
537// int8_t so that an integer and not a character is printed.
538template <typename TagType, typename ValidatorType>
539std::ostream& operator<<(std::ostream& os,
540 StrongInt<TagType, int8_t, ValidatorType> arg) {
541 return os << static_cast<int>(arg.value());
542}
543
544// Provide the << operator, primarily for logging purposes. Specialized for
545// uint8_t so that an integer and not a character is printed.
546template <typename TagType, typename ValidatorType>
547std::ostream& operator<<(std::ostream& os,
548 StrongInt<TagType, uint8_t, ValidatorType> arg) {
549 return os << static_cast<unsigned int>(arg.value());
550}
551
552// Define operators that take two StrongInt arguments.
553#define STRONG_INT_VS_STRONG_INT_BINARY_OP(op, validator) \
554 template <typename TagType, typename ValueType, typename ValidatorType> \
555 constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
556 StrongInt<TagType, ValueType, ValidatorType> lhs, \
557 StrongInt<TagType, ValueType, ValidatorType> rhs) { \
558 return ValidatorType::template validator<ValueType>(lhs.value(), \
559 rhs.value()), \
560 StrongInt<TagType, ValueType, ValidatorType>( \
561 static_cast<ValueType>(lhs.value() op rhs.value())); \
562 }
564STRONG_INT_VS_STRONG_INT_BINARY_OP(-, ValidateSubtract);
565STRONG_INT_VS_STRONG_INT_BINARY_OP(&, ValidateBitAnd);
566STRONG_INT_VS_STRONG_INT_BINARY_OP(|, ValidateBitOr);
567STRONG_INT_VS_STRONG_INT_BINARY_OP(^, ValidateBitXor);
568#undef STRONG_INT_VS_STRONG_INT_BINARY_OP
569
570// Define operators that take one StrongInt and one native arithmetic argument.
571#define STRONG_INT_VS_NUMERIC_BINARY_OP(op, validator) \
572 template <typename TagType, typename ValueType, typename ValidatorType, \
573 typename NumType, \
574 std::enable_if_t<!IsStrongIntV<NumType>>* = nullptr> \
575 constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
576 StrongInt<TagType, ValueType, ValidatorType> lhs, NumType rhs) { \
577 return ValidatorType::template validator<ValueType>(lhs.value(), rhs), \
578 StrongInt<TagType, ValueType, ValidatorType>( \
579 static_cast<ValueType>(lhs.value() op rhs)); \
580 }
581// This is used for commutative operators between one StrongInt and one native
582// integer argument. That is a long way of saying "multiplication".
583#define NUMERIC_VS_STRONG_INT_BINARY_OP(op, validator) \
584 template <typename TagType, typename ValueType, typename ValidatorType, \
585 typename NumType, \
586 std::enable_if_t<!IsStrongIntV<NumType>>* = nullptr> \
587 constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
588 NumType lhs, StrongInt<TagType, ValueType, ValidatorType> rhs) { \
589 return ValidatorType::template validator<ValueType>(rhs.value(), lhs), \
590 StrongInt<TagType, ValueType, ValidatorType>( \
591 static_cast<ValueType>(rhs.value() op lhs)); \
592 }
593STRONG_INT_VS_NUMERIC_BINARY_OP(*, ValidateMultiply);
594NUMERIC_VS_STRONG_INT_BINARY_OP(*, ValidateMultiply);
595STRONG_INT_VS_NUMERIC_BINARY_OP(/, ValidateDivide);
596STRONG_INT_VS_NUMERIC_BINARY_OP(%, ValidateModulo);
597STRONG_INT_VS_NUMERIC_BINARY_OP(<<, ValidateLeftShift);
598STRONG_INT_VS_NUMERIC_BINARY_OP(>>, ValidateRightShift);
599#undef STRONG_INT_VS_NUMERIC_BINARY_OP
600#undef NUMERIC_VS_STRONG_INT_BINARY_OP
601
602// Define comparison operators. We allow all comparison operators.
603#define STRONG_INT_COMPARISON_OP(op) \
604 template <typename TagType, typename ValueType, typename ValidatorType> \
605 constexpr bool operator op( \
606 StrongInt<TagType, ValueType, ValidatorType> lhs, \
607 StrongInt<TagType, ValueType, ValidatorType> rhs) { \
608 return lhs.value() op rhs.value(); \
609 }
610STRONG_INT_COMPARISON_OP(==); // NOLINT(whitespace/operators)
611STRONG_INT_COMPARISON_OP(!=); // NOLINT(whitespace/operators)
612STRONG_INT_COMPARISON_OP(<); // NOLINT(whitespace/operators)
613STRONG_INT_COMPARISON_OP(<=); // NOLINT(whitespace/operators)
614STRONG_INT_COMPARISON_OP(>); // NOLINT(whitespace/operators)
615STRONG_INT_COMPARISON_OP(>=); // NOLINT(whitespace/operators)
616#undef STRONG_INT_COMPARISON_OP
617
618// Support for-range loops. Enables easier looping over ranges of StrongInts,
619// especially looping over sub-ranges of StrongVectors.
620template <typename IntType>
621class StrongIntRange {
622 public:
623 // Iterator over the indices.
624 class StrongIntRangeIterator {
625 public:
626 using value_type = IntType;
627 using difference_type = IntType;
628 using reference = const IntType&;
629 using pointer = const IntType*;
630 using iterator_category = std::input_iterator_tag;
631
632 explicit StrongIntRangeIterator(IntType initial) : current_(initial) {}
633 bool operator!=(const StrongIntRangeIterator& other) const {
634 return current_ != other.current_;
635 }
636 bool operator==(const StrongIntRangeIterator& other) const {
637 return current_ == other.current_;
638 }
639 value_type operator*() const { return current_; }
640 pointer operator->() const { return &current_; }
641 StrongIntRangeIterator& operator++() {
642 ++current_;
643 return *this;
644 }
645 StrongIntRangeIterator operator++(int) {
646 StrongIntRangeIterator old_iter = *this;
647 ++current_;
648 return old_iter;
649 }
650
651 private:
652 IntType current_;
653 };
654
655 // Loops from IntType(0) up to (but not including) end.
656 explicit StrongIntRange(IntType end) : begin_(IntType(0)), end_(end) {}
657 // Loops from begin up to (but not including) end.
658 StrongIntRange(IntType begin, IntType end) : begin_(begin), end_(end) {}
659 StrongIntRangeIterator begin() const { return begin_; }
660 StrongIntRangeIterator end() const { return end_; }
661
662 private:
663 const StrongIntRangeIterator begin_;
664 const StrongIntRangeIterator end_;
665};
666
667template <typename IntType>
668StrongIntRange<IntType> MakeStrongIntRange(IntType end) {
669 return StrongIntRange<IntType>(end);
670}
671
672template <typename IntType>
673StrongIntRange<IntType> MakeStrongIntRange(IntType begin, IntType end) {
674 return StrongIntRange<IntType>(begin, end);
675}
676
677} // namespace util_intops
678
679// Defines the StrongInt using value_type and typedefs it to type_name, with no
680// validation of under/overflow situations.
681// The struct int_type_name ## _tag_ trickery is needed to ensure that a new
682// type is created per type_name.
683#define DEFINE_STRONG_INT_TYPE(type_name, value_type) \
684 struct type_name##_strong_int_tag_ { \
685 static constexpr absl::string_view TypeName() { return #type_name; } \
686 }; \
687 typedef ::util_intops::StrongInt<type_name##_strong_int_tag_, value_type, \
688 ::util_intops::NullStrongIntValidator> \
689 type_name;
690
691// Numeric_limits override for strong int.
692namespace std {
693// Allow StrongInt to be used as a key to hashable containers.
694// NOLINTNEXTLINE(google3-runtime-std-hash-specialization)
695template <typename Tag, typename Value, typename Validator>
696struct hash<util_intops::StrongInt<Tag, Value, Validator>>
697 : ::util_intops::StrongInt<Tag, Value, Validator>::Hasher {};
698
699template <typename TagType, typename NativeType, typename ValidatorType>
700struct numeric_limits<
701 util_intops::StrongInt<TagType, NativeType, ValidatorType>> {
702 private:
703 using StrongIntT = util_intops::StrongInt<TagType, NativeType, ValidatorType>;
704
705 public:
706 // NOLINTBEGIN(google3-readability-class-member-naming)
707 static constexpr bool is_specialized = true;
708 static constexpr bool is_signed = numeric_limits<NativeType>::is_signed;
709 static constexpr bool is_integer = numeric_limits<NativeType>::is_integer;
710 static constexpr bool is_exact = numeric_limits<NativeType>::is_exact;
711 static constexpr bool has_infinity = numeric_limits<NativeType>::has_infinity;
712 static constexpr bool has_quiet_NaN =
713 numeric_limits<NativeType>::has_quiet_NaN;
714 static constexpr bool has_signaling_NaN =
715 numeric_limits<NativeType>::has_signaling_NaN;
716 static constexpr float_denorm_style has_denorm =
717 numeric_limits<NativeType>::has_denorm;
718 static constexpr bool has_denorm_loss =
719 numeric_limits<NativeType>::has_denorm_loss;
720 static constexpr float_round_style round_style =
721 numeric_limits<NativeType>::round_style;
722 static constexpr bool is_iec559 = numeric_limits<NativeType>::is_iec559;
723 static constexpr bool is_bounded = numeric_limits<NativeType>::is_bounded;
724 static constexpr bool is_modulo = numeric_limits<NativeType>::is_modulo;
725 static constexpr int digits = numeric_limits<NativeType>::digits;
726 static constexpr int digits10 = numeric_limits<NativeType>::digits10;
727 static constexpr int max_digits10 = numeric_limits<NativeType>::max_digits10;
728 static constexpr int radix = numeric_limits<NativeType>::radix;
729 static constexpr int min_exponent = numeric_limits<NativeType>::min_exponent;
730 static constexpr int min_exponent10 =
731 numeric_limits<NativeType>::min_exponent10;
732 static constexpr int max_exponent = numeric_limits<NativeType>::max_exponent;
733 static constexpr int max_exponent10 =
734 numeric_limits<NativeType>::max_exponent10;
735 static constexpr bool traps = numeric_limits<NativeType>::traps;
736 static constexpr bool tinyness_before =
737 numeric_limits<NativeType>::tinyness_before;
738 // NOLINTEND(google3-readability-class-member-naming)
739
740 static constexpr StrongIntT(min)() { return StrongIntT(StrongIntT::Min()); }
741 static constexpr StrongIntT lowest() { return StrongIntT(StrongIntT::Min()); }
742 static constexpr StrongIntT(max)() { return StrongIntT(StrongIntT::Max()); }
743 static constexpr StrongIntT epsilon() { return StrongIntT(); }
744 static constexpr StrongIntT round_error() { return StrongIntT(); }
745 static constexpr StrongIntT infinity() { return StrongIntT(); }
746 static constexpr StrongIntT quiet_NaN() { return StrongIntT(); }
747 static constexpr StrongIntT signaling_NaN() { return StrongIntT(); }
748 static constexpr StrongIntT denorm_min() { return StrongIntT(); }
749};
750
751} // namespace std
752
753#endif // OR_TOOLS_BASE_STRONG_INT_H_
bool AbslParseFlag(absl::string_view text, FileFormat *f, std::string *error)
std::string AbslUnparseFlag(FileFormat f)
bool operator!=(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)
bool operator==(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)
void AbslStringify(Sink &sink, const AttrT attr_type)
Definition attributes.h:336
H AbslHashValue(H h, std::shared_ptr< Variable > i)
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
LinearExpr operator*(LinearExpr lhs, double rhs)
LinearExpr operator-(LinearExpr lhs, const LinearExpr &rhs)
ClosedInterval::Iterator end(ClosedInterval interval)
LinearExpr operator+(LinearExpr lhs, const LinearExpr &rhs)
ClosedInterval::Iterator begin(ClosedInterval interval)
STL namespace.
std::ostream & operator<<(std::ostream &out, const std::pair< First, Second > &p)
Definition stl_logging.h:99
#define NUMERIC_VS_STRONG_INT_BINARY_OP(op, validator)
#define STRONG_INT_VS_STRONG_INT_BINARY_OP(op, validator)
#define STRONG_INT_COMPARISON_OP(op)
#define STRONG_INT_VS_NUMERIC_BINARY_OP(op, validator)