1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 **************************************************************************/
19 #ifndef REALM_UTIL_TYPE_TRAITS_HPP
20 #define REALM_UTIL_TYPE_TRAITS_HPP
26 #include <type_traits>
28 #include <realm/util/features.h>
29 #include <realm/util/assert.hpp>
30 #include <realm/util/type_list.hpp>
35 template <class From, class To>
38 typedef typename std::remove_const<To>::type type_1;
41 typedef typename std::conditional<std::is_const<From>::value, const type_1, type_1>::type type;
45 /// Member `type` is the type resulting from integral or
46 /// floating-point promotion of a value of type `T`.
48 /// \note Enum types are supported only when the compiler supports the
49 /// C++11 'decltype' feature.
54 /// Member `type` is the type of the result of a binary arithmetic (or
55 /// bitwise) operation (+, -, *, /, %, |, &, ^) when applied to
56 /// operands of type `A` and `B` respectively. The type of the result
57 /// of a shift operation (<<, >>) can instead be found as the type
58 /// resulting from integral promotion of the left operand. The type of
59 /// the result of a unary arithmetic (or bitwise) operation can be
60 /// found as the type resulting from integral promotion of the
63 /// \note Enum types are supported only when the compiler supports the
64 /// C++11 'decltype' feature.
65 template <class A, class B>
66 struct ArithBinOpType;
69 /// Member `type` is `B` if `B` has more value bits than `A`,
70 /// otherwise is is `A`.
71 template <class A, class B>
72 struct ChooseWidestInt;
75 /// Member `type` is the first of `unsigned char`, `unsigned short`,
76 /// `unsigned int`, `unsigned long`, and `unsigned long long` that has
77 /// at least `bits` value bits.
82 /// Member `type` is `unsigned` if `unsigned` has at least `bits`
83 /// value bits, otherwise it is the same as
84 /// `LeastUnsigned<bits>::%type`.
86 struct FastestUnsigned;
94 typedef decltype(+T()) type; // FIXME: This is not performing floating-point promotion.
98 template <class A, class B>
99 struct ArithBinOpType {
100 typedef decltype(A() + B()) type;
104 template <class A, class B>
105 struct ChooseWidestInt {
107 typedef std::numeric_limits<A> lim_a;
108 typedef std::numeric_limits<B> lim_b;
109 static_assert(lim_a::is_specialized && lim_b::is_specialized,
110 "std::numeric_limits<> must be specialized for both types");
111 static_assert(lim_a::is_integer && lim_b::is_integer, "Both types must be integers");
114 typedef typename std::conditional<(lim_a::digits >= lim_b::digits), A, B>::type type;
119 struct LeastUnsigned {
121 typedef void types_0;
122 typedef TypeAppend<types_0, unsigned char>::type types_1;
123 typedef TypeAppend<types_1, unsigned short>::type types_2;
124 typedef TypeAppend<types_2, unsigned int>::type types_3;
125 typedef TypeAppend<types_3, unsigned long>::type types_4;
126 typedef TypeAppend<types_4, unsigned long long>::type types_5;
127 typedef types_5 types;
128 // The `dummy<>` template is there to work around a bug in
129 // VisualStudio (seen in versions 2010 and 2012). Without the
130 // `dummy<>` template, The C++ compiler in Visual Studio would
131 // attempt to instantiate `FindType<type, pred>` before the
132 // instantiation of `LeastUnsigned<>` which obviously fails
133 // because `pred` depends on `bits`.
138 static const bool value = std::numeric_limits<T>::digits >= bits;
143 typedef typename FindType<types, dummy<bits>::template pred>::type type;
144 static_assert(!(std::is_same<type, void>::value), "No unsigned type is that wide");
149 struct FastestUnsigned {
151 typedef typename util::LeastUnsigned<bits>::type least_unsigned;
154 typedef typename util::ChooseWidestInt<unsigned, least_unsigned>::type type;
161 #endif // REALM_UTIL_TYPE_TRAITS_HPP