Fork/duplicate a local DEFINE_STRONG_INT_TYPE and DEFINE_STRING_TYPE.
PiperOrigin-RevId: 435355118
diff --git a/rs_bindings_from_cc/blaze_types.h b/rs_bindings_from_cc/blaze_types.h
index af1f34d..10863ff 100644
--- a/rs_bindings_from_cc/blaze_types.h
+++ b/rs_bindings_from_cc/blaze_types.h
@@ -5,13 +5,14 @@
#ifndef CRUBIT_RS_BINDINGS_FROM_CC_BLAZE_TYPES_H_
#define CRUBIT_RS_BINDINGS_FROM_CC_BLAZE_TYPES_H_
-#include "third_party/absl/strings/string_view.h"
-#include "util/gtl/labs/string_type.h"
+#include <string>
+
+#include "rs_bindings_from_cc/util/string_type.h"
namespace rs_bindings_from_cc {
// Representation of a Blaze label (for example //foo/bar:baz).
-DEFINE_STRING_TYPE(BlazeLabel);
+CRUBIT_DEFINE_STRING_TYPE(BlazeLabel);
} // namespace rs_bindings_from_cc
diff --git a/rs_bindings_from_cc/cmdline.h b/rs_bindings_from_cc/cmdline.h
index bfe701e..6fe85e2 100644
--- a/rs_bindings_from_cc/cmdline.h
+++ b/rs_bindings_from_cc/cmdline.h
@@ -42,7 +42,7 @@
absl::string_view ir_out() const { return ir_out_; }
bool do_nothing() const { return do_nothing_; }
- const std::vector<rs_bindings_from_cc::HeaderName>& public_headers() const {
+ const std::vector<HeaderName>& public_headers() const {
return public_headers_;
}
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index a949ad5..10099d4 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -16,8 +16,8 @@
#include "base/integral_types.h"
#include "third_party/absl/strings/string_view.h"
#include "rs_bindings_from_cc/bazel_types.h"
+#include "rs_bindings_from_cc/util/strong_int.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
-#include "util/intops/strong_int.h"
namespace rs_bindings_from_cc {
@@ -27,12 +27,12 @@
}
template <typename TTag, typename TInt>
-llvm::json::Value toJSON(const util_intops::StrongInt<TTag, TInt> strong_int) {
+llvm::json::Value toJSON(const StrongInt<TTag, TInt> strong_int) {
return llvm::json::Value(strong_int.value());
}
template <typename TTag>
-llvm::json::Value toJSON(const gtl::labs::StringType<TTag> string_type) {
+llvm::json::Value toJSON(const StringType<TTag> string_type) {
return llvm::json::Value(string_type.value());
}
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index 2411f34..1dadd71 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -25,11 +25,11 @@
#include "base/logging.h"
#include "third_party/absl/strings/string_view.h"
#include "rs_bindings_from_cc/bazel_types.h"
+#include "rs_bindings_from_cc/util/strong_int.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/APSInt.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/FormatVariadic.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/JSON.h"
-#include "util/intops/strong_int.h"
namespace rs_bindings_from_cc {
@@ -77,10 +77,10 @@
// serialization/deserialization at the moment, we need a way to restore graph
// edges that don't follow the JSON tree structure (for example between types
// and records). We use DeclIds for this.
-DEFINE_STRONG_INT_TYPE(DeclId, uintptr_t);
+CRUBIT_DEFINE_STRONG_INT_TYPE(DeclId, uintptr_t);
// A numerical ID that uniquely identifies a lifetime.
-DEFINE_STRONG_INT_TYPE(LifetimeId, int);
+CRUBIT_DEFINE_STRONG_INT_TYPE(LifetimeId, int);
// A lifetime.
struct Lifetime {
diff --git a/rs_bindings_from_cc/util/README b/rs_bindings_from_cc/util/README
new file mode 100644
index 0000000..1244391
--- /dev/null
+++ b/rs_bindings_from_cc/util/README
@@ -0,0 +1,2 @@
+`util` subdirectory contains various utilities. Some of them are
+forked copies of internal Google libraries that are not included in Abseil.
diff --git a/rs_bindings_from_cc/util/string_type.h b/rs_bindings_from_cc/util/string_type.h
new file mode 100644
index 0000000..81717f8
--- /dev/null
+++ b/rs_bindings_from_cc/util/string_type.h
@@ -0,0 +1,261 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Typed strings.
+
+// Example usage:
+//
+// CRUBIT_DEFINE_STRING_TYPE(Foo);
+// CRUBIT_DEFINE_STRING_TYPE(Bar);
+// Foo foo("foo_value");
+// Bar bar("bar_value");
+//
+// The following two statements will not compile.
+//
+// foo = bar;
+//
+// if (foo == bar) { } else { }; ...
+//
+// The strongly-typed types are hashable with the Abseil hashing framework,
+// so they work out of the box with any modern hashing system. For non-Abseil
+// uses, the explicit functors absl::Hash<Foo>, absl::Hash<Bar> may be used:
+//
+// std::unordered_set<Foo, absl::Hash<Foo>>
+// __gnu_cxx::hash_map<Bar, int, absl::Hash<Bar>>
+//
+// (But absl::flat_hash_set<Foo> is much better!)
+
+#ifndef CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRING_TYPE_H_
+#define CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRING_TYPE_H_
+
+#include <memory>
+#include <ostream> // NOLINT
+#include <string>
+
+#include "third_party/absl/container/flat_hash_set.h"
+#include "third_party/absl/flags/marshalling.h"
+#include "third_party/absl/meta/type_traits.h"
+#include "third_party/absl/strings/string_view.h"
+
+// Defines the StringType using StringTypeRepresentation and provides a type
+// alias to string_type_name. The struct string_type_name ## _tag_ trickery is
+// needed to ensure that a new type is created per string_type_name.
+//
+// StringTypeRepresentation classes, as a rule, should either *be* a string-like
+// object, or should provide a "value()" method that returns a string-like
+// object. If they can provide more optimal implementations of relational
+// operators, they should define operator== and operator<; all other relational
+// operators are defined in terms of those. If they can provide more optimal
+// implementations of AbslHashValue or operator<<, they should provide those as
+// well.
+#define CRUBIT_DEFINE_STRING_TYPE_AS(string_type_name, \
+ StringTypeRepresentation) \
+ struct string_type_name##_tag_ { \
+ static absl::string_view TypeName() { return #string_type_name; } \
+ using Representation = StringTypeRepresentation; \
+ }; \
+ using string_type_name = \
+ ::rs_bindings_from_cc::StringType<string_type_name##_tag_>;
+
+#define CRUBIT_DEFINE_STRING_TYPE(string_type_name) \
+ CRUBIT_DEFINE_STRING_TYPE_AS(string_type_name, std::string);
+
+namespace rs_bindings_from_cc {
+
+// StringType provides these operations:
+// * relational operators (==, !=, <, <=, >, >=)
+// * compare (future <=> operator)
+// * AbslHashValue
+// * streaming with operator<<
+// * value(), which should return a string-like object (const string&,
+// absl::string_view, ShortString<N>, etc.)
+//
+// It is parameterized here by a "TagAndRepresentation" struct. It's a unique
+// struct defined in each CRUBIT_DEFINE_STRING_TYPE_AS macro invocation, so
+// every StringType is its own unique, strong type. In addition, it provides a
+// static TypeName() method that returns the name of the type, and it provides a
+// "Representation" type alias which is held as a member by each StringType
+// instance.
+//
+// When a StringType instance method is called, it will first try to dispatch
+// the call directly to the Representation instance. If the Representation
+// class doesn't have this method, StringType will call value() on its
+// representation instance, and then call the method on the returned value.
+// We do this dispatch at compile-time using <internal link>.
+template <typename TagAndRepresentation>
+class StringType {
+ public:
+ // Shorthand.
+ using Rep = typename TagAndRepresentation::Representation;
+
+ private:
+ // Using SFINAE, you can "rank" implementations using this mechanism. Given
+ // two acceptable implementations that substitute correctly, the compiler will
+ // choose the one that requires fewer type conversions, so a method given a
+ // Rank0 object will prefer an implementation that accepts a Rank0 type to an
+ // implementation that accepts a Rank1 type, since a Rank1 argument requires a
+ // derived->base conversion.
+ struct Rank1 {};
+ struct Rank0 : Rank1 {};
+
+ // This would normally be declared at the bottom of the class, but we need to
+ // move it up here to satisfy the compiler.
+ //
+ // Since the return type of value(), below, is either the same as the return
+ // type of t_.value(), if such a method exists, or t_ itself, if t_.value()
+ // doesn't exists, we need to declare our t_ up here so the compiler knows
+ // what it is and whether it has a value() method.
+ Rep t_;
+
+ // These must be defined before value() is defined below, since value()'s
+ // return type is determined by what these methods return.
+ template <typename T>
+ static auto DispatchValue(const T& t, Rank0) -> decltype(t.value()) {
+ return t.value();
+ }
+ static const Rep& DispatchValue(const Rep& t, Rank1) { return t; }
+
+ public:
+ StringType() = default;
+ template <typename T, typename = absl::enable_if_t<
+ std::is_constructible<Rep, T&&>::value>>
+ explicit StringType(T&& value) : t_(std::forward<T>(value)) {}
+
+ // Returns the name of this StringType, as used in code.
+ static absl::string_view TypeName() {
+ return TagAndRepresentation::TypeName();
+ }
+
+ ABSL_DEPRECATED("Use TypeName()")
+ static absl::string_view TypeId() { return TypeName(); }
+
+ // Returns the result of the representation's value() method, or the
+ // representation itself if the representation has no value() method.
+ auto value() const -> decltype(DispatchValue(t_, Rank0{})) {
+ return DispatchValue(t_, Rank0{});
+ }
+
+ bool empty() const { return DispatchEmpty(t_, Rank0{}); }
+
+ // If you want to optimize your relational methods, you need only implement
+ // these three: compare, operator==, and operator<.
+ int compare(const StringType& other) const {
+ return DispatchCompare(*this, other, Rank0{});
+ }
+ friend bool operator==(const StringType& left, const StringType& right) {
+ return DispatchEquals(left, right, Rank0{});
+ }
+ friend bool operator<(const StringType& left, const StringType& right) {
+ return DispatchLessThan(left, right, Rank0{});
+ }
+
+ // These methods are defined in terms of the above.
+ friend bool operator!=(const StringType& left, const StringType& right) {
+ return !(left == right);
+ }
+ friend bool operator>(const StringType& left, const StringType& right) {
+ return right < left;
+ }
+ friend bool operator<=(const StringType& left, const StringType& right) {
+ return !(left > right);
+ }
+ friend bool operator>=(const StringType& left, const StringType& right) {
+ return !(left < right);
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const StringType& s) {
+ return s.DispatchHash(std::move(h), Rank0{});
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const StringType& s) {
+ return DispatchOstream(os, s.t_, Rank0{});
+ }
+
+ private:
+ template <typename T>
+ static auto DispatchEmpty(const T& t, Rank0) -> decltype(t.empty()) {
+ return t.empty();
+ }
+ static bool DispatchEmpty(const Rep& t, Rank1) {
+ return DispatchValue(t, Rank0{}).empty();
+ }
+
+ // This overload exists specifically for absl::Cord, which spells 'compare' as
+ // 'Compare'.
+ template <typename T>
+ static auto DispatchCompare(const T& left, const T& right, Rank0)
+ -> decltype(left.value().Compare(right.value())) {
+ return left.value().Compare(right.value());
+ }
+ template <typename T>
+ static auto DispatchCompare(const T& left, const T& right, Rank0)
+ -> decltype(left.t_.compare(right.t_)) {
+ return left.t_.compare(right.t_);
+ }
+ template <typename T>
+ static auto DispatchCompare(const T& left, const T& right, Rank1)
+ -> decltype(left.value().compare(right.value())) {
+ return left.value().compare(right.value());
+ }
+
+ template <typename T>
+ static auto DispatchEquals(const T& left, const T& right, Rank0)
+ -> decltype(left.t_ == right.t_) {
+ return left.t_ == right.t_;
+ }
+ static bool DispatchEquals(const StringType& left, const StringType& right,
+ Rank1) {
+ return left.value() == right.value();
+ }
+
+ template <typename T>
+ static auto DispatchLessThan(const T& left, const T& right, Rank0)
+ -> decltype(left.t_ < right.t_) {
+ return left.t_ < right.t_;
+ }
+ static bool DispatchLessThan(const StringType& left, const StringType& right,
+ Rank1) {
+ return left.value() < right.value();
+ }
+
+ template <
+ typename H, typename T = Rep,
+ typename Hashable = decltype(absl::Hash<T>()(std::declval<const T&>()))>
+ H DispatchHash(H h, Rank0) const {
+ return H::combine(std::move(h), t_);
+ }
+ template <typename H>
+ H DispatchHash(H h, Rank1) const {
+ return H::combine(std::move(h), value());
+ }
+
+ template <typename T>
+ static auto DispatchOstream(std::ostream& os, const T& t, Rank0)
+ -> decltype(os << t) {
+ return os << t;
+ }
+ static std::ostream& DispatchOstream(std::ostream& os, const Rep& t, Rank1) {
+ return os << DispatchValue(t, Rank0{});
+ }
+};
+
+// Allows typed strings to be used as ABSL_FLAG values.
+//
+// This is equivalent in behavior to just using a raw std::string.
+template <typename TagAndRepresentation>
+bool AbslParseFlag(absl::string_view text,
+ StringType<TagAndRepresentation>* out, std::string* error) {
+ *out = StringType<TagAndRepresentation>(text);
+ return true;
+}
+
+template <typename TagAndRepresentation>
+std::string AbslUnparseFlag(const StringType<TagAndRepresentation>& val) {
+ return absl::UnparseFlag(std::string(val.value()));
+}
+
+} // namespace rs_bindings_from_cc
+
+#endif // CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRING_TYPE_H_
diff --git a/rs_bindings_from_cc/util/strong_int.h b/rs_bindings_from_cc/util/strong_int.h
new file mode 100644
index 0000000..1e11223
--- /dev/null
+++ b/rs_bindings_from_cc/util/strong_int.h
@@ -0,0 +1,658 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// StrongInt<T> is a simple template class mechanism for defining "logical"
+// integer-like class types that support almost all of the same functionality
+// as native integer types, but which prevents assignment, construction, and
+// other operations from other integer-like types. In other words, you cannot
+// assign from raw integer types or other StrongInt<> types, nor can you do
+// most arithmetic or logical operations. This provides a simple form of
+// dimensionality in that you can add two instances of StrongInt<T>, producing
+// a StrongInt<T>, but you can not add a StrongInt<T> and a raw T nor can you
+// add a StrongInt<T> and a StrongInt<U>. Details on supported operations are
+// below.
+//
+// In addition to type strength, StrongInt provides a way to inject (optional)
+// validation of the various operations. This allows you to define StrongInt
+// types that check for overflow conditions and react in standard or custom
+// ways.
+//
+// A StrongInt<T> with a NullStrongIntValidator should compile away to a raw T
+// in optimized mode. What this means is that the generated assembly for:
+//
+// int64 foo = 123;
+// int64 bar = 456;
+// int64 baz = foo + bar;
+// constexpr int64 fubar = 789;
+//
+// ...should be identical to the generated assembly for:
+//
+// CRUBIT_DEFINE_STRONG_INT_TYPE(MyStrongInt, int64);
+// MyStrongInt foo(123);
+// MyStrongInt bar(456);
+// MyStrongInt baz = foo + bar;
+// constexpr MyStrongInt fubar(789);
+//
+// Since the methods are all inline and non-virtual and the class has just
+// one data member, the compiler can erase the StrongInt class entirely in its
+// code-generation phase. This also means that you can pass StrongInt<T>
+// around by value just as you would a raw T.
+//
+// It is important to note that StrongInt does NOT generate compile time
+// warnings or errors for overflows on implicit constant conversions.
+// For example, the below demonstrates a case where the 2 are not equivalent
+// at compile time and can lead to subtle initialization bugs:
+//
+// CRUBIT_DEFINE_STRONG_INT_TYPE(MyStrongInt8, int8);
+// int8 foo = 1024; // Compile error: const conversion to ...
+// MyStrongInt8 foo(1024); // Compiles ok: foo has undefined / 0 value.
+//
+// Usage:
+// CRUBIT_DEFINE_STRONG_INT_TYPE(Name, NativeType);
+//
+// Defines a new StrongInt type named 'Name' in the current namespace with
+// no validation of operations.
+//
+// Name: The desired name for the new StrongInt typedef. Must be unique
+// within the current namespace.
+// NativeType: The primitive integral type this StrongInt will hold, as
+// defined by std::numeric_limits::is_integer (see <type_traits>).
+//
+// StrongInt<TagType, NativeType, ValidatorType = NullStrongIntValidator>
+//
+// Creates a new StrongInt instance directly.
+//
+// TagType: The unique type which discriminates this StrongInt<T> from
+// other StrongInt<U> types.
+// NativeType: The primitive integral type this StrongInt will hold, as
+// defined by std::numeric_limits::is_integer (see <type_traits>).
+// ValidatorType: The type of validation used by this StrongInt type. A
+// few pre-built validator types are provided here, but the caller can
+// define any custom validator they desire.
+//
+// Supported operations:
+// StrongInt<T> = StrongInt<T>
+// !StrongInt<T> => bool
+// ~StrongInt<T> => StrongInt<T>
+// -StrongInt<T> => StrongInt<T>
+// +StrongInt<T> => StrongInt<T>
+// ++StrongInt<T> => StrongInt<T>
+// StrongInt<T>++ => StrongInt<T>
+// --StrongInt<T> => StrongInt<T>
+// StrongInt<T>-- => StrongInt<T>
+// StrongInt<T> + StrongInt<T> => StrongInt<T>
+// StrongInt<T> - StrongInt<T> => StrongInt<T>
+// StrongInt<T> * (numeric type) => StrongInt<T>
+// StrongInt<T> / (numeric type) => StrongInt<T>
+// StrongInt<T> % (numeric type) => StrongInt<T>
+// StrongInt<T> << (numeric type) => StrongInt<T>
+// StrongInt<T> >> (numeric type) => StrongInt<T>
+// StrongInt<T> & StrongInt<T> => StrongInt<T>
+// StrongInt<T> | StrongInt<T> => StrongInt<T>
+// StrongInt<T> ^ StrongInt<T> => StrongInt<T>
+//
+// For binary operations, the equivalent op-equal (eg += vs. +) operations are
+// also supported. Other operator combinations should cause compile-time
+// errors.
+//
+// This class also provides a .value() accessor method and defines a hash
+// functor that allows the IntType to be used as key to hashable containers.
+//
+// Validators:
+// NullStrongIntValidator: Do no validation. This should be entirely
+// optimized away by the compiler.
+
+#ifndef CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRONG_INT_H_
+#define CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRONG_INT_H_
+
+#include <cstdint>
+#include <hash_map>
+#include <iosfwd>
+#include <iterator>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+
+#include "third_party/absl/base/macros.h"
+#include "third_party/absl/meta/type_traits.h"
+#include "third_party/absl/strings/string_view.h"
+
+namespace rs_bindings_from_cc {
+
+// Define the validators which can be plugged-in to make StrongInt resilient to
+// things like overflows. This is a do-nothing implementation of the
+// compile-time interface.
+//
+// NOTE: For all validation functions that operate on an existing StrongInt<T>,
+// the type argument 'T' *must* be StrongInt<T>::ValueType (the int type being
+// strengthened).
+//
+struct NullStrongIntValidator {
+ // Note that this templated default implementation has an arbitrary bool
+ // return value for the sole purpose of conforming to c++11 constexpr.
+ //
+ // Custom validator implementations can choose to return void or use a similar
+ // return value constexpr construct if constexpr initialization is desirable.
+ //
+ // The StrongInt class does not care about or use the returned value. Any
+ // returned value is solely there to allow the constexpr declaration; custom
+ // validators can only fail / abort when detecting an invalid value.
+ //
+ // For example, other than the constexpr behavior, the below 2 custom
+ // validator implementations are logically equivalent:
+ //
+ // template<typename T, typename U>
+ // static void ValidateInit(U arg) {
+ // if (arg < 0) LOG(FATAL) << "arg < 0";
+ // }
+ //
+ // template<typename T, typename U>
+ // static constexpr bool ValidateInit(U arg) {
+ // return (arg < 0) ? (LOG(FATAL) << "arg < 0", false) : false;
+ // }
+ //
+ // A constexpr implementation has the added advantage that the validation can
+ // take place (fail) at compile time.
+
+ // Verify initialization of StrongInt<T> from arg, type U.
+ template<typename T, typename U>
+ static constexpr bool ValidateInit(U arg) { return true; }
+ // Verify -value.
+ template <typename T>
+ static constexpr bool ValidateNegate(T /*value*/) {
+ return true;
+ }
+ // Verify ~value;
+ template <typename T>
+ static constexpr bool ValidateBitNot(T /*value*/) {
+ return true;
+ }
+ // Verify lhs + rhs.
+ template <typename T>
+ static constexpr bool ValidateAdd(T /*lhs*/, T /*rhs*/) {
+ return true;
+ }
+ // Verify lhs - rhs.
+ template <typename T>
+ static constexpr bool ValidateSubtract(T /*lhs*/, T /*rhs*/) {
+ return true;
+ }
+ // Verify lhs * rhs.
+ template <typename T, typename U>
+ static constexpr bool ValidateMultiply(T /*lhs*/, U /*rhs*/) {
+ return true;
+ }
+ // Verify lhs / rhs.
+ template <typename T, typename U>
+ static constexpr bool ValidateDivide(T /*lhs*/, U /*rhs*/) {
+ return true;
+ }
+ // Verify lhs % rhs.
+ template <typename T, typename U>
+ static constexpr bool ValidateModulo(T /*lhs*/, U /*rhs*/) {
+ return true;
+ }
+ // Verify lhs << rhs.
+ template <typename T>
+ static constexpr bool ValidateLeftShift(T /*lhs*/, int64_t /*rhs*/) {
+ return true;
+ }
+ // Verify lhs >> rhs.
+ template <typename T>
+ static constexpr bool ValidateRightShift(T /*lhs*/, int64_t /*rhs*/) {
+ return true;
+ }
+ // Verify lhs & rhs.
+ template <typename T>
+ static constexpr bool ValidateBitAnd(T /*lhs*/, T /*rhs*/) {
+ return true;
+ }
+ // Verify lhs | rhs.
+ template <typename T>
+ static constexpr bool ValidateBitOr(T /*lhs*/, T /*rhs*/) {
+ return true;
+ }
+ // Verify lhs ^ rhs.
+ template <typename T>
+ static constexpr bool ValidateBitXor(T /*lhs*/, T /*rhs*/) {
+ return true;
+ }
+};
+
+// Holds an integer value (of type NativeType) and behaves as a NativeType by
+// exposing assignment, unary, comparison, and arithmetic operators.
+//
+// This class is NOT thread-safe.
+template<typename TagType, typename NativeType,
+ typename ValidatorType = NullStrongIntValidator>
+class StrongInt {
+ public:
+ typedef NativeType ValueType;
+
+ struct ABSL_DEPRECATED("Use absl::Hash instead") Hasher {
+ size_t operator()(const StrongInt &x) const {
+ return static_cast<size_t>(x.value());
+ }
+ };
+
+ static constexpr absl::string_view TypeName() { return TagType::TypeName(); }
+
+ // Default value initialization.
+ constexpr StrongInt()
+ : value_((ValidatorType::template ValidateInit<ValueType>(NativeType()),
+ NativeType())) {}
+
+ // Explicit initialization from another StrongInt type that has an
+ // implementation of:
+ //
+ // ToType StrongIntConvert(FromType source, ToType*);
+ //
+ // This uses Argument Dependent Lookup (ADL) to find which function to
+ // call.
+ //
+ // Example: Assume you have two StrongInt types.
+ //
+ // CRUBIT_DEFINE_STRONG_INT_TYPE(Bytes, int64);
+ // CRUBIT_DEFINE_STRONG_INT_TYPE(Megabytes, int64);
+ //
+ // If you want to be able to (explicitly) construct an instance of Bytes from
+ // an instance of Megabytes, simply define a converter function in the same
+ // namespace as either Bytes or Megabytes (or both):
+ //
+ // Megabytes StrongIntConvert(Bytes arg, Megabytes* /* unused */) {
+ // return Megabytes((arg >> 20).value());
+ // };
+ //
+ // The second argument is needed to differentiate conversions, and it always
+ // passed as NULL.
+ template <typename ArgTagType, typename ArgNativeType,
+ typename ArgValidatorType>
+ explicit constexpr StrongInt(
+ StrongInt<ArgTagType, ArgNativeType, ArgValidatorType> arg)
+ // We have to pass both the "from" type and the "to" type as args for the
+ // conversions to be differentiated. The converter can not be a template
+ // because explicit template call syntax defeats ADL.
+ : value_(
+ StrongIntConvert(arg, static_cast<StrongInt *>(nullptr)).value()) {}
+
+ // Explicit initialization from a numeric primitive.
+ template <
+ class T,
+ class = std::enable_if_t<std::is_same_v<
+ decltype(static_cast<ValueType>(std::declval<T>())), ValueType>>>
+ explicit constexpr StrongInt(T init_value)
+ : value_((ValidatorType::template ValidateInit<ValueType>(init_value),
+ static_cast<ValueType>(init_value))) {}
+
+ // Use the default copy constructor, assignment, and destructor.
+
+ // Accesses the raw value.
+ constexpr ValueType value() const { return value_; }
+
+ // Accesses the raw value, with cast.
+ // Primarily for compatibility with int-type.h
+ template <typename ValType>
+ constexpr ValType value() const { return static_cast<ValType>(value_); }
+
+ // Explicitly cast the raw value only if the underlying value is convertible
+ // to T.
+ template <typename T,
+ typename = absl::enable_if_t<absl::conjunction<
+ std::bool_constant<std::numeric_limits<T>::is_integer>,
+ std::is_convertible<ValueType, T>>::value>>
+ constexpr explicit operator T() const {
+ return value_;
+ }
+
+ // Metadata functions.
+ static constexpr StrongInt Max() {
+ return StrongInt(std::numeric_limits<ValueType>::max());
+ }
+ static constexpr StrongInt Min() {
+ return StrongInt(std::numeric_limits<ValueType>::min());
+ }
+
+ // Unary operators.
+ bool operator!() const {
+ return value_ == 0;
+ }
+ const StrongInt operator+() const {
+ return StrongInt(value_);
+ }
+ const StrongInt operator-() const {
+ ValidatorType::template ValidateNegate<ValueType>(value_);
+ return StrongInt(-value_);
+ }
+ const StrongInt operator~() const {
+ ValidatorType::template ValidateBitNot<ValueType>(value_);
+ return StrongInt(ValueType(~value_));
+ }
+
+ // Increment and decrement operators.
+ StrongInt &operator++() { // ++x
+ ValidatorType::template ValidateAdd<ValueType>(value_, ValueType(1));
+ ++value_;
+ return *this;
+ }
+ const StrongInt operator++(int postfix_flag) { // x++
+ ValidatorType::template ValidateAdd<ValueType>(value_, ValueType(1));
+ StrongInt temp(*this);
+ ++value_;
+ return temp;
+ }
+ StrongInt &operator--() { // --x
+ ValidatorType::template ValidateSubtract<ValueType>(value_, ValueType(1));
+ --value_;
+ return *this;
+ }
+ const StrongInt operator--(int postfix_flag) { // x--
+ ValidatorType::template ValidateSubtract<ValueType>(value_, ValueType(1));
+ StrongInt temp(*this);
+ --value_;
+ return temp;
+ }
+
+ // Action-Assignment operators.
+ StrongInt &operator+=(StrongInt arg) {
+ ValidatorType::template ValidateAdd<ValueType>(value_, arg.value());
+ value_ += arg.value();
+ return *this;
+ }
+ StrongInt &operator-=(StrongInt arg) {
+ ValidatorType::template ValidateSubtract<ValueType>(value_, arg.value());
+ value_ -= arg.value();
+ return *this;
+ }
+ template<typename ArgType>
+ StrongInt &operator*=(ArgType arg) {
+ ValidatorType::template ValidateMultiply<ValueType, ArgType>(value_, arg);
+ value_ *= arg;
+ return *this;
+ }
+ template<typename ArgType>
+ StrongInt &operator/=(ArgType arg) {
+ ValidatorType::template ValidateDivide<ValueType, ArgType>(value_, arg);
+ value_ /= arg;
+ return *this;
+ }
+ template<typename ArgType>
+ StrongInt &operator%=(ArgType arg) {
+ ValidatorType::template ValidateModulo<ValueType, ArgType>(value_, arg);
+ value_ %= arg;
+ return *this;
+ }
+ StrongInt &operator<<=(int64_t arg) { // NOLINT(whitespace/operators)
+ ValidatorType::template ValidateLeftShift<ValueType>(value_, arg);
+ value_ <<= arg;
+ return *this;
+ }
+ StrongInt &operator>>=(int64_t arg) { // NOLINT(whitespace/operators)
+ ValidatorType::template ValidateRightShift<ValueType>(value_, arg);
+ value_ >>= arg;
+ return *this;
+ }
+ StrongInt &operator&=(StrongInt arg) {
+ ValidatorType::template ValidateBitAnd<ValueType>(value_, arg.value());
+ value_ &= arg.value();
+ return *this;
+ }
+ StrongInt &operator|=(StrongInt arg) {
+ ValidatorType::template ValidateBitOr<ValueType>(value_, arg.value());
+ value_ |= arg.value();
+ return *this;
+ }
+ StrongInt &operator^=(StrongInt arg) {
+ ValidatorType::template ValidateBitXor<ValueType>(value_, arg.value());
+ value_ ^= arg.value();
+ return *this;
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const StrongInt &i) {
+ return H::combine(std::move(h), i.value_);
+ }
+
+ private:
+ // The integer value of type ValueType.
+ ValueType value_;
+
+ static_assert(std::numeric_limits<ValueType>::is_integer,
+ "invalid integer type for strong int");
+};
+
+// Provide the << operator, primarily for logging purposes.
+template<typename TagType, typename ValueType, typename ValidatorType>
+std::ostream &operator<<(std::ostream &os,
+ StrongInt<TagType, ValueType, ValidatorType> arg) {
+ return os << arg.value();
+}
+
+// Provide the << operator, primarily for logging purposes. Specialized for int8
+// so that an integer and not a character is printed.
+template <typename TagType, typename ValidatorType>
+std::ostream &operator<<(std::ostream &os,
+ StrongInt<TagType, int8_t, ValidatorType> arg) {
+ return os << static_cast<int>(arg.value());
+}
+
+// Provide the << operator, primarily for logging purposes. Specialized for
+// uint8 so that an integer and not a character is printed.
+template <typename TagType, typename ValidatorType>
+std::ostream &operator<<(std::ostream &os,
+ StrongInt<TagType, uint8_t, ValidatorType> arg) {
+ return os << static_cast<unsigned int>(arg.value());
+}
+
+// Define operators that take two StrongInt arguments.
+#define CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(op, validator) \
+ template <typename TagType, typename ValueType, typename ValidatorType> \
+ constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
+ StrongInt<TagType, ValueType, ValidatorType> lhs, \
+ StrongInt<TagType, ValueType, ValidatorType> rhs) { \
+ return ValidatorType::template validator<ValueType>(lhs.value(), \
+ rhs.value()), \
+ StrongInt<TagType, ValueType, ValidatorType>( \
+ static_cast<ValueType>(lhs.value() op rhs.value())); \
+ }
+CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(+, ValidateAdd);
+CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(-, ValidateSubtract);
+CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(&, ValidateBitAnd);
+CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(|, ValidateBitOr);
+CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP(^, ValidateBitXor);
+#undef CRUBIT_STRONG_INT_VS_STRONG_INT_BINARY_OP
+
+// Define operators that take one StrongInt and one native integer argument.
+// These operators are defined in terms of their op-equal member function
+// cousins, mostly.
+#define CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(op, validator) \
+ template <typename TagType, typename ValueType, typename ValidatorType, \
+ typename NumType> \
+ constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
+ StrongInt<TagType, ValueType, ValidatorType> lhs, NumType rhs) { \
+ return ValidatorType::template validator<ValueType>(lhs.value(), rhs), \
+ StrongInt<TagType, ValueType, ValidatorType>( \
+ static_cast<ValueType>(lhs.value() op rhs)); \
+ }
+// This is used for commutative operators between one StrongInt and one native
+// integer argument. That is a long way of saying "multiplication".
+#define CRUBIT_NUMERIC_VS_STRONG_INT_BINARY_OP(op, validator) \
+ template <typename TagType, typename ValueType, typename ValidatorType, \
+ typename NumType> \
+ constexpr StrongInt<TagType, ValueType, ValidatorType> operator op( \
+ NumType lhs, StrongInt<TagType, ValueType, ValidatorType> rhs) { \
+ return ValidatorType::template validator<ValueType>(rhs.value(), lhs), \
+ StrongInt<TagType, ValueType, ValidatorType>( \
+ static_cast<ValueType>(rhs.value() op lhs)); \
+ }
+CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(*, ValidateMultiply);
+CRUBIT_NUMERIC_VS_STRONG_INT_BINARY_OP(*, ValidateMultiply);
+CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(/, ValidateDivide);
+CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(%, ValidateModulo);
+CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(<<, ValidateLeftShift);
+CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP(>>, ValidateRightShift);
+#undef CRUBIT_STRONG_INT_VS_NUMERIC_BINARY_OP
+#undef CRUBIT_NUMERIC_VS_STRONG_INT_BINARY_OP
+
+// Define comparison operators. We allow all comparison operators.
+#define CRUBIT_STRONG_INT_COMPARISON_OP(op) \
+ template <typename TagType, typename ValueType, typename ValidatorType> \
+ constexpr bool operator op( \
+ StrongInt<TagType, ValueType, ValidatorType> lhs, \
+ StrongInt<TagType, ValueType, ValidatorType> rhs) { \
+ return lhs.value() op rhs.value(); \
+ }
+CRUBIT_STRONG_INT_COMPARISON_OP(==); // NOLINT(whitespace/operators)
+CRUBIT_STRONG_INT_COMPARISON_OP(!=); // NOLINT(whitespace/operators)
+CRUBIT_STRONG_INT_COMPARISON_OP(<); // NOLINT(whitespace/operators)
+CRUBIT_STRONG_INT_COMPARISON_OP(<=); // NOLINT(whitespace/operators)
+CRUBIT_STRONG_INT_COMPARISON_OP(>); // NOLINT(whitespace/operators)
+CRUBIT_STRONG_INT_COMPARISON_OP(>=); // NOLINT(whitespace/operators)
+#undef CRUBIT_STRONG_INT_COMPARISON_OP
+
+// Support for-range loops. Enables easier looping over ranges of StrongInts,
+// especially looping over sub-ranges of StrongVectors.
+template <typename IntType>
+class StrongIntRange {
+ public:
+ // Iterator over the indices.
+ class StrongIntRangeIterator {
+ public:
+ using value_type = IntType;
+ using difference_type = IntType;
+ using reference = const IntType &;
+ using pointer = const IntType *;
+ using iterator_category = std::input_iterator_tag;
+
+ explicit StrongIntRangeIterator(IntType initial) : current_(initial) {}
+ bool operator!=(const StrongIntRangeIterator &other) const {
+ return current_ != other.current_;
+ }
+ bool operator==(const StrongIntRangeIterator &other) const {
+ return current_ == other.current_;
+ }
+ value_type operator*() const { return current_; }
+ pointer operator->() const { return ¤t_; }
+ StrongIntRangeIterator &operator++() {
+ ++current_;
+ return *this;
+ }
+ StrongIntRangeIterator operator++(int) {
+ StrongIntRangeIterator old_iter = *this;
+ ++current_;
+ return old_iter;
+ }
+
+ private:
+ IntType current_;
+ };
+
+ // Loops from IntType(0) up to (but not including) end.
+ explicit StrongIntRange(IntType end) : begin_(IntType(0)), end_(end) {}
+ // Loops from begin up to (but not including) end.
+ StrongIntRange(IntType begin, IntType end) : begin_(begin), end_(end) {}
+ StrongIntRangeIterator begin() const { return begin_; }
+ StrongIntRangeIterator end() const { return end_; }
+
+ private:
+ const StrongIntRangeIterator begin_;
+ const StrongIntRangeIterator end_;
+};
+
+template <typename IntType>
+StrongIntRange<IntType> MakeStrongIntRange(IntType end) {
+ return StrongIntRange<IntType>(end);
+}
+
+template <typename IntType>
+StrongIntRange<IntType> MakeStrongIntRange(IntType begin, IntType end) {
+ return StrongIntRange<IntType>(begin, end);
+}
+
+// Type trait for detecting if a type T is a StrongInt type.
+template <typename T>
+struct IsStrongInt : public std::false_type {};
+
+template <typename... Ts>
+struct IsStrongInt<StrongInt<Ts...>> : public std::true_type {};
+
+} // namespace rs_bindings_from_cc
+
+// Defines the StrongInt using value_type and typedefs it to type_name, with no
+// validation of under/overflow situations.
+// The struct int_type_name ## _tag_ trickery is needed to ensure that a new
+// type is created per type_name.
+#define CRUBIT_DEFINE_STRONG_INT_TYPE(type_name, value_type) \
+ struct type_name##_strong_int_tag_ { \
+ static constexpr absl::string_view TypeName() { return #type_name; } \
+ }; \
+ typedef ::rs_bindings_from_cc::StrongInt< \
+ type_name##_strong_int_tag_, value_type, \
+ ::rs_bindings_from_cc::NullStrongIntValidator> \
+ type_name;
+
+// Allow StrongInt to be used as a key to hashable containers.
+HASH_NAMESPACE_DECLARATION_START
+template <typename Tag, typename Value, typename Validator>
+struct hash<rs_bindings_from_cc::StrongInt<Tag, Value, Validator>>
+ : ::rs_bindings_from_cc::StrongInt<Tag, Value, Validator>::Hasher {};
+HASH_NAMESPACE_DECLARATION_END
+
+// Numeric_limits override for strong int.
+namespace std {
+
+template <typename TagType, typename NativeType, typename ValidatorType>
+struct numeric_limits<
+ rs_bindings_from_cc::StrongInt<TagType, NativeType, ValidatorType>> {
+ private:
+ using StrongIntT =
+ rs_bindings_from_cc::StrongInt<TagType, NativeType, ValidatorType>;
+
+ public:
+ static constexpr bool is_specialized = true;
+ static constexpr bool is_signed = numeric_limits<NativeType>::is_signed;
+ static constexpr bool is_integer = numeric_limits<NativeType>::is_integer;
+ static constexpr bool is_exact = numeric_limits<NativeType>::is_exact;
+ static constexpr bool has_infinity = numeric_limits<NativeType>::has_infinity;
+ static constexpr bool has_quiet_NaN =
+ numeric_limits<NativeType>::has_quiet_NaN;
+ static constexpr bool has_signaling_NaN =
+ numeric_limits<NativeType>::has_signaling_NaN;
+ static constexpr float_denorm_style has_denorm =
+ numeric_limits<NativeType>::has_denorm;
+ static constexpr bool has_denorm_loss =
+ numeric_limits<NativeType>::has_denorm_loss;
+ static constexpr float_round_style round_style =
+ numeric_limits<NativeType>::round_style;
+ static constexpr bool is_iec559 = numeric_limits<NativeType>::is_iec559;
+ static constexpr bool is_bounded = numeric_limits<NativeType>::is_bounded;
+ static constexpr bool is_modulo = numeric_limits<NativeType>::is_modulo;
+ static constexpr int digits = numeric_limits<NativeType>::digits;
+ static constexpr int digits10 = numeric_limits<NativeType>::digits10;
+ static constexpr int max_digits10 = numeric_limits<NativeType>::max_digits10;
+ static constexpr int radix = numeric_limits<NativeType>::radix;
+ static constexpr int min_exponent = numeric_limits<NativeType>::min_exponent;
+ static constexpr int min_exponent10 =
+ numeric_limits<NativeType>::min_exponent10;
+ static constexpr int max_exponent = numeric_limits<NativeType>::max_exponent;
+ static constexpr int max_exponent10 =
+ numeric_limits<NativeType>::max_exponent10;
+ static constexpr bool traps = numeric_limits<NativeType>::traps;
+ static constexpr bool tinyness_before =
+ numeric_limits<NativeType>::tinyness_before;
+
+ static constexpr StrongIntT(min)() { return StrongIntT(StrongIntT::Min()); }
+ static constexpr StrongIntT lowest() { return StrongIntT(StrongIntT::Min()); }
+ static constexpr StrongIntT(max)() { return StrongIntT(StrongIntT::Max()); }
+ static constexpr StrongIntT epsilon() { return StrongIntT(); }
+ static constexpr StrongIntT round_error() { return StrongIntT(); }
+ static constexpr StrongIntT infinity() { return StrongIntT(); }
+ static constexpr StrongIntT quiet_NaN() { return StrongIntT(); }
+ static constexpr StrongIntT signaling_NaN() { return StrongIntT(); }
+ static constexpr StrongIntT denorm_min() { return StrongIntT(); }
+};
+
+} // namespace std
+
+#endif // CRUBIT_RS_BINDINGS_FROM_CC_UTIL_STRONG_INT_H_