aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/core/lib/gtl/int_type.h
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/core/lib/gtl/int_type.h')
-rw-r--r--tensorflow/core/lib/gtl/int_type.h343
1 files changed, 343 insertions, 0 deletions
diff --git a/tensorflow/core/lib/gtl/int_type.h b/tensorflow/core/lib/gtl/int_type.h
new file mode 100644
index 0000000000..d3fcb08d38
--- /dev/null
+++ b/tensorflow/core/lib/gtl/int_type.h
@@ -0,0 +1,343 @@
+// #status: LEGACY
+// #category: Miscellaneous
+// #summary: Integral types; prefer util/intops/strong_int.h
+// #bugs: Infrastructure > C++ Library Team > util
+//
+// IntType is a simple template class mechanism for defining "logical"
+// integer-like class types that support many of the same functionalities
+// as native integer types, but which prevent assignment, construction, and
+// other operations from other similar integer-like types. Essentially, the
+// template class IntType<IntTypeName, ValueType> (where ValueType assumes
+// valid scalar types such as int, uint, int32, etc) has the additional
+// property that it cannot be assigned to or constructed from other IntTypes
+// or native integer types of equal or implicitly convertible type.
+//
+// The class is useful for preventing mingling of integer variables with
+// different logical roles or units. Unfortunately, C++ provides relatively
+// good type-safety for user-defined classes but not for integer types. It is
+// essentially up to the user to use nice variable names and comments to prevent
+// accidental mismatches, such as confusing a user-index with a group-index or a
+// time-in-milliseconds with a time-in-seconds. The use of typedefs are limited
+// in that regard as they do not enforce type-safety.
+//
+// USAGE -----------------------------------------------------------------------
+//
+// DEFINE_INT_TYPE(IntTypeName, ValueType);
+//
+// where:
+// IntTypeName: is the desired (unique) name for the "logical" integer type.
+// ValueType: is one of the integral types as defined by base::is_integral
+// (see base/type_traits.h).
+//
+// DISALLOWED OPERATIONS / TYPE-SAFETY ENFORCEMENT -----------------------------
+//
+// Consider these definitions and variable declarations:
+// DEFINE_INT_TYPE(GlobalDocID, int64);
+// DEFINE_INT_TYPE(LocalDocID, int64);
+// GlobalDocID global;
+// LocalDocID local;
+//
+// The class IntType prevents:
+//
+// 1) Assignments of other IntTypes with different IntTypeNames.
+//
+// global = local; <-- Fails to compile!
+// local = global; <-- Fails to compile!
+//
+// 2) Explicit/implicit conversion from an IntType to another IntType.
+//
+// LocalDocID l(global); <-- Fails to compile!
+// LocalDocID l = global; <-- Fails to compile!
+//
+// void GetGlobalDoc(GlobalDocID global) { }
+// GetGlobalDoc(global); <-- Compiles fine, types match!
+// GetGlobalDoc(local); <-- Fails to compile!
+//
+// 3) Implicit conversion from an IntType to a native integer type.
+//
+// void GetGlobalDoc(int64 global) { ...
+// GetGlobalDoc(global); <-- Fails to compile!
+// GetGlobalDoc(local); <-- Fails to compile!
+//
+// void GetLocalDoc(int32 local) { ...
+// GetLocalDoc(global); <-- Fails to compile!
+// GetLocalDoc(local); <-- Fails to compile!
+//
+//
+// SUPPORTED OPERATIONS --------------------------------------------------------
+//
+// The following operators are supported: unary: ++ (both prefix and postfix),
+// +, -, ! (logical not), ~ (one's complement); comparison: ==, !=, <, <=, >,
+// >=; numerical: +, -, *, /; assignment: =, +=, -=, /=, *=; stream: <<. Each
+// operator allows the same IntTypeName and the ValueType to be used on
+// both left- and right-hand sides.
+//
+// It also supports an accessor value() returning the stored value as ValueType,
+// and a templatized accessor value<T>() method that serves as syntactic sugar
+// for static_cast<T>(var.value()). These accessors are useful when assigning
+// the stored value into protocol buffer fields and using it as printf args.
+//
+// The class also defines a hash functor that allows the IntType to be used
+// as key to hashable containers such as std::unordered_map and
+// std::unordered_set.
+//
+// We suggest using the IntTypeIndexedContainer wrapper around FixedArray and
+// STL vector (see int-type-indexed-container.h) if an IntType is intended to
+// be used as an index into these containers. These wrappers are indexed in a
+// type-safe manner using IntTypes to ensure type-safety.
+//
+// NB: this implementation does not attempt to abide by or enforce dimensional
+// analysis on these scalar types.
+//
+// EXAMPLES --------------------------------------------------------------------
+//
+// DEFINE_INT_TYPE(GlobalDocID, int64);
+// GlobalDocID global = 3;
+// cout << global; <-- Prints 3 to stdout.
+//
+// for (GlobalDocID i(0); i < global; ++i) {
+// cout << i;
+// } <-- Print(ln)s 0 1 2 to stdout
+//
+// DEFINE_INT_TYPE(LocalDocID, int64);
+// LocalDocID local;
+// cout << local; <-- Prints 0 to stdout it default
+// initializes the value to 0.
+//
+// local = 5;
+// local *= 2;
+// LocalDocID l(local);
+// cout << l + local; <-- Prints 20 to stdout.
+//
+// GenericSearchRequest request;
+// request.set_doc_id(global.value()); <-- Uses value() to extract the value
+// from the IntType class.
+//
+// REMARKS ---------------------------------------------------------------------
+//
+// The following bad usage is permissible although discouraged. Essentially, it
+// involves using the value*() accessors to extract the native integer type out
+// of the IntType class. Keep in mind that the primary reason for the IntType
+// class is to prevent *accidental* mingling of similar logical integer types --
+// and not type casting from one type to another.
+//
+// DEFINE_INT_TYPE(GlobalDocID, int64);
+// DEFINE_INT_TYPE(LocalDocID, int64);
+// GlobalDocID global;
+// LocalDocID local;
+//
+// global = local.value(); <-- Compiles fine.
+//
+// void GetGlobalDoc(GlobalDocID global) { ...
+// GetGlobalDoc(local.value()); <-- Compiles fine.
+//
+// void GetGlobalDoc(int64 global) { ...
+// GetGlobalDoc(local.value()); <-- Compiles fine.
+
+#ifndef TENSORFLOW_LIB_GTL_INT_TYPE_H_
+#define TENSORFLOW_LIB_GTL_INT_TYPE_H_
+
+#include <stddef.h>
+#include <functional>
+#include <iosfwd>
+#include <ostream> // NOLINT
+#include <unordered_map>
+
+#include "tensorflow/core/platform/port.h"
+
+namespace tensorflow {
+namespace gtl {
+
+template <typename IntTypeName, typename _ValueType>
+class IntType;
+
+// Defines the IntType using value_type and typedefs it to int_type_name.
+// The struct int_type_name ## _tag_ trickery is needed to ensure that a new
+// type is created per int_type_name.
+#define TF_LIB_GTL_DEFINE_INT_TYPE(int_type_name, value_type) \
+ struct int_type_name##_tag_ {}; \
+ typedef ::tensorflow::gtl::IntType<int_type_name##_tag_, value_type> \
+ int_type_name;
+
+// Holds an integer value (of type ValueType) and behaves as a ValueType by
+// exposing assignment, unary, comparison, and arithmetic operators.
+//
+// The template parameter IntTypeName defines the name for the int type and must
+// be unique within a binary (the convenient DEFINE_INT_TYPE macro at the end of
+// the file generates a unique IntTypeName). The parameter ValueType defines
+// the integer type value (see supported list above).
+//
+// This class is NOT thread-safe.
+template <typename IntTypeName, typename _ValueType>
+class IntType {
+ public:
+ typedef _ValueType ValueType; // for non-member operators
+ typedef IntType<IntTypeName, ValueType> ThisType; // Syntactic sugar.
+
+ // Note that this may change from time to time without notice.
+ struct Hasher {
+ size_t operator()(const IntType& arg) const {
+ return static_cast<size_t>(arg.value());
+ }
+ };
+
+ public:
+ // Default c'tor initializing value_ to 0.
+ constexpr IntType() : value_(0) {}
+ // C'tor explicitly initializing from a ValueType.
+ constexpr explicit IntType(ValueType value) : value_(value) {}
+
+ // IntType uses the default copy constructor, destructor and assign operator.
+ // The defaults are sufficient and omitting them allows the compiler to add
+ // the move constructor/assignment.
+
+ // -- ACCESSORS --------------------------------------------------------------
+ // The class provides a value() accessor returning the stored ValueType value_
+ // as well as a templatized accessor that is just a syntactic sugar for
+ // static_cast<T>(var.value());
+ constexpr ValueType value() const { return value_; }
+
+ template <typename ValType>
+ constexpr ValType value() const {
+ return static_cast<ValType>(value_);
+ }
+
+ // -- UNARY OPERATORS --------------------------------------------------------
+ ThisType& operator++() { // prefix ++
+ ++value_;
+ return *this;
+ }
+ const ThisType operator++(int v) { // postfix ++
+ ThisType temp(*this);
+ ++value_;
+ return temp;
+ }
+ ThisType& operator--() { // prefix --
+ --value_;
+ return *this;
+ }
+ const ThisType operator--(int v) { // postfix --
+ ThisType temp(*this);
+ --value_;
+ return temp;
+ }
+
+ constexpr bool operator!() const { return value_ == 0; }
+ constexpr const ThisType operator+() const { return ThisType(value_); }
+ constexpr const ThisType operator-() const { return ThisType(-value_); }
+ constexpr const ThisType operator~() const { return ThisType(~value_); }
+
+// -- ASSIGNMENT OPERATORS ---------------------------------------------------
+// We support the following assignment operators: =, +=, -=, *=, /=, <<=, >>=
+// and %= for both ThisType and ValueType.
+#define INT_TYPE_ASSIGNMENT_OP(op) \
+ ThisType& operator op(const ThisType& arg_value) { \
+ value_ op arg_value.value(); \
+ return *this; \
+ } \
+ ThisType& operator op(ValueType arg_value) { \
+ value_ op arg_value; \
+ return *this; \
+ }
+ INT_TYPE_ASSIGNMENT_OP(+= );
+ INT_TYPE_ASSIGNMENT_OP(-= );
+ INT_TYPE_ASSIGNMENT_OP(*= );
+ INT_TYPE_ASSIGNMENT_OP(/= );
+ INT_TYPE_ASSIGNMENT_OP(<<= ); // NOLINT
+ INT_TYPE_ASSIGNMENT_OP(>>= ); // NOLINT
+ INT_TYPE_ASSIGNMENT_OP(%= );
+#undef INT_TYPE_ASSIGNMENT_OP
+
+ ThisType& operator=(ValueType arg_value) {
+ value_ = arg_value;
+ return *this;
+ }
+
+ private:
+ // The integer value of type ValueType.
+ ValueType value_;
+
+ static_assert(std::is_integral<ValueType>::value, "invalid integer type");
+} TF_PACKED;
+
+// -- NON-MEMBER STREAM OPERATORS ----------------------------------------------
+// We provide the << operator, primarily for logging purposes. Currently, there
+// seems to be no need for an >> operator.
+template <typename IntTypeName, typename ValueType>
+std::ostream& operator<<(std::ostream& os, // NOLINT
+ IntType<IntTypeName, ValueType> arg) {
+ return os << arg.value();
+}
+
+// -- NON-MEMBER ARITHMETIC OPERATORS ------------------------------------------
+// We support only the +, -, *, and / operators with the same IntType and
+// ValueType types. The reason is to allow simple manipulation on these IDs
+// when used as indices in vectors and arrays.
+//
+// NB: Although it is possible to do IntType * IntType and IntType / IntType,
+// it is probably non-sensical from a dimensionality analysis perspective.
+#define INT_TYPE_ARITHMETIC_OP(op) \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr IntType<IntTypeName, ValueType> operator op( \
+ IntType<IntTypeName, ValueType> id_1, \
+ IntType<IntTypeName, ValueType> id_2) { \
+ return IntType<IntTypeName, ValueType>(id_1.value() op id_2.value()); \
+ } \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr IntType<IntTypeName, ValueType> operator op( \
+ IntType<IntTypeName, ValueType> id, \
+ typename IntType<IntTypeName, ValueType>::ValueType arg_val) { \
+ return IntType<IntTypeName, ValueType>(id.value() op arg_val); \
+ } \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr IntType<IntTypeName, ValueType> operator op( \
+ typename IntType<IntTypeName, ValueType>::ValueType arg_val, \
+ IntType<IntTypeName, ValueType> id) { \
+ return IntType<IntTypeName, ValueType>(arg_val op id.value()); \
+ }
+INT_TYPE_ARITHMETIC_OP(+);
+INT_TYPE_ARITHMETIC_OP(-);
+INT_TYPE_ARITHMETIC_OP(*);
+INT_TYPE_ARITHMETIC_OP(/ );
+INT_TYPE_ARITHMETIC_OP(<< ); // NOLINT
+INT_TYPE_ARITHMETIC_OP(>> ); // NOLINT
+INT_TYPE_ARITHMETIC_OP(% );
+#undef INT_TYPE_ARITHMETIC_OP
+
+// -- NON-MEMBER COMPARISON OPERATORS ------------------------------------------
+// Static inline comparison operators. We allow all comparison operators among
+// the following types (OP \in [==, !=, <, <=, >, >=]:
+// IntType<IntTypeName, ValueType> OP IntType<IntTypeName, ValueType>
+// IntType<IntTypeName, ValueType> OP ValueType
+// ValueType OP IntType<IntTypeName, ValueType>
+#define INT_TYPE_COMPARISON_OP(op) \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr bool operator op( \
+ IntType<IntTypeName, ValueType> id_1, \
+ IntType<IntTypeName, ValueType> id_2) { \
+ return id_1.value() op id_2.value(); \
+ } \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr bool operator op( \
+ IntType<IntTypeName, ValueType> id, \
+ typename IntType<IntTypeName, ValueType>::ValueType val) { \
+ return id.value() op val; \
+ } \
+ template <typename IntTypeName, typename ValueType> \
+ static inline constexpr bool operator op( \
+ typename IntType<IntTypeName, ValueType>::ValueType val, \
+ IntType<IntTypeName, ValueType> id) { \
+ return val op id.value(); \
+ }
+INT_TYPE_COMPARISON_OP(== ); // NOLINT
+INT_TYPE_COMPARISON_OP(!= ); // NOLINT
+INT_TYPE_COMPARISON_OP(< ); // NOLINT
+INT_TYPE_COMPARISON_OP(<= ); // NOLINT
+INT_TYPE_COMPARISON_OP(> ); // NOLINT
+INT_TYPE_COMPARISON_OP(>= ); // NOLINT
+#undef INT_TYPE_COMPARISON_OP
+
+} // namespace gtl
+} // namespace tensorflow
+
+#endif // TENSORFLOW_LIB_GTL_INT_TYPE_H_