added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / safe_int_ops.hpp
diff --git a/iOS/Pods/Realm/include/core/realm/util/safe_int_ops.hpp b/iOS/Pods/Realm/include/core/realm/util/safe_int_ops.hpp
new file mode 100644 (file)
index 0000000..15030ad
--- /dev/null
@@ -0,0 +1,623 @@
+/*************************************************************************
+ *
+ * Copyright 2016 Realm Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************/
+
+#ifndef REALM_UTIL_SAFE_INT_OPS_HPP
+#define REALM_UTIL_SAFE_INT_OPS_HPP
+
+#ifdef _WIN32
+#undef max // collides with numeric_limits::max called later in this header file
+#undef min // collides with numeric_limits::min called later in this header file
+#endif
+
+#include <limits>
+
+#include <realm/util/features.h>
+#include <realm/util/assert.hpp>
+#include <realm/util/type_traits.hpp>
+
+namespace realm {
+namespace util {
+
+
+/// Perform integral or floating-point promotion on the argument. This
+/// is useful for example when printing a number of arbitrary numeric
+/// type to 'stdout', since it will convert values of character-like
+/// types to regular integer types, which will then be printed as
+/// numbers rather characters.
+template <class T>
+typename Promote<T>::type promote(T value) noexcept;
+
+
+/// This function allows you to test for a negative value in any
+/// numeric type, even when the type is unsigned. Normally, when the
+/// type is unsigned, such a test will produce a compiler warning.
+template <class T>
+bool is_negative(T value) noexcept;
+
+
+/// Cast the specified value to the specified unsigned type reducing
+/// the value (or in case of negative values, the two's complement
+/// representation) modulo `2**N` where `N` is the number of value
+/// bits (or digits) in the unsigned target type. This is usefull in
+/// cases where the target type may be `bool`, but need not be `bool`.
+template <class To, class From>
+To cast_to_unsigned(From) noexcept;
+
+
+//@{
+
+/// Compare two integers of the same, or of different type, and
+/// produce the expected result according to the natural
+/// interpretation of the operation.
+///
+/// Note that in general a standard comparison between a signed and an
+/// unsigned integer type is unsafe, and it often generates a compiler
+/// warning. An example is a 'less than' comparison between a negative
+/// value of type 'int' and a small positive value of type
+/// 'unsigned'. In this case the negative value will be converted to
+/// 'unsigned' producing a large positive value which, in turn, will
+/// lead to the counter intuitive result of 'false'.
+///
+/// Please note that these operation incur absolutely no overhead when
+/// the two types have the same signedness.
+///
+/// These functions check at compile time that both types have valid
+/// specializations of std::numeric_limits<> and that both are indeed
+/// integers.
+///
+/// These functions make absolutely no assumptions about the platform
+/// except that it complies with at least C++03.
+
+template <class A, class B>
+inline bool int_equal_to(A, B) noexcept;
+template <class A, class B>
+inline bool int_not_equal_to(A, B) noexcept;
+template <class A, class B>
+inline bool int_less_than(A, B) noexcept;
+template <class A, class B>
+inline bool int_less_than_or_equal(A, B) noexcept;
+template <class A, class B>
+inline bool int_greater_than(A, B) noexcept;
+template <class A, class B>
+inline bool int_greater_than_or_equal(A, B) noexcept;
+
+//@}
+
+
+//@{
+
+/// Check for overflow in integer variable `lval` while adding integer
+/// `rval` to it, or while subtracting integer `rval` from it. Returns
+/// true on positive or negative overflow.
+///
+/// Both `lval` and `rval` must be of an integer type for which a
+/// specialization of std::numeric_limits<> exists. The two types need
+/// not be the same, in particular, one can be signed and the other
+/// one can be unsigned.
+///
+/// These functions are especially well suited for cases where \a rval
+/// is a compile-time constant.
+///
+/// These functions check at compile time that both types have valid
+/// specializations of std::numeric_limits<> and that both are indeed
+/// integers.
+///
+/// These functions make absolutely no assumptions about the platform
+/// except that it complies with at least C++03.
+
+template <class L, class R>
+inline bool int_add_with_overflow_detect(L& lval, R rval) noexcept;
+
+template <class L, class R>
+inline bool int_subtract_with_overflow_detect(L& lval, R rval) noexcept;
+
+//@}
+
+
+/// Check for positive overflow when multiplying two positive integers
+/// of the same, or of different type. Returns true on overflow.
+///
+/// \param lval Must not be negative. Both signed and unsigned types
+/// can be used.
+///
+/// \param rval Must be stricly greater than zero. Both signed and
+/// unsigned types can be used.
+///
+/// This function is especially well suited for cases where \a rval is
+/// a compile-time constant.
+///
+/// This function checks at compile time that both types have valid
+/// specializations of std::numeric_limits<> and that both are indeed
+/// integers.
+///
+/// This function makes absolutely no assumptions about the platform
+/// except that it complies with at least C++03.
+template <class L, class R>
+inline bool int_multiply_with_overflow_detect(L& lval, R rval) noexcept;
+
+
+/// Checks for positive overflow when performing a bitwise shift to
+/// the left on a non-negative value of arbitrary integer
+/// type. Returns true on overflow.
+///
+/// \param lval Must not be negative. Both signed and unsigned types
+/// can be used.
+///
+/// \param i Must be non-negative and such that <tt>L(1)>>i</tt> has a
+/// value that is defined by the C++03 standard. In particular, the
+/// value of i must not exceed the number of bits of storage type T as
+/// shifting by this amount is not defined by the standard.
+///
+/// This function makes absolutely no assumptions about the platform
+/// except that it complies with at least C++03.
+template <class T>
+inline bool int_shift_left_with_overflow_detect(T& lval, int i) noexcept;
+
+
+//@{
+
+/// Check for overflow when casting an integer value from one type to
+/// another. While the first function is a mere check, the second one
+/// also carries out the cast, but only when there is no
+/// overflow. Both return true on overflow.
+///
+/// These functions check at compile time that both types have valid
+/// specializations of std::numeric_limits<> and that both are indeed
+/// integers.
+///
+/// These functions make absolutely no assumptions about the platform
+/// except that it complies with at least C++03.
+
+template <class To, class From>
+bool int_cast_has_overflow(From from) noexcept;
+
+template <class To, class From>
+bool int_cast_with_overflow_detect(From from, To& to) noexcept;
+
+//@}
+
+
+/// Convert negative values from two's complement representation to the
+/// platforms native representation.
+///
+/// If `To` is an unsigned type, this function does nothing beyond casting the
+/// specified value to `To`. Otherwise, `To` is a signed type, and negative
+/// values will be converted from two's complement representation in unsigned
+/// `From` to the platforms native representation in `To`.
+///
+/// For signed `To` the result is well-defined if, and only if the value with
+/// the specified two's complement representation is representable in the
+/// specified signed type. While this is generally the case when using
+/// corresponding signed/unsigned type pairs, it is not guaranteed by the
+/// standard. However, if you know that the signed type has at least as many
+/// value bits as the unsigned type, then the result is always
+/// well-defined. Note that a 'value bit' in this context is the same as a
+/// 'digit' from the point of view of `std::numeric_limits`.
+///
+/// On platforms that use two's complement representation of negative values,
+/// this function is expected to be completely optimized away. This has been
+/// observed to be true with both GCC 4.8 and Clang 3.2.
+///
+/// Note that the **opposite** direction (from the platforms native
+/// representation to two's complement) is trivially handled by casting the
+/// signed value to a value of a sufficiently wide unsigned integer type. An
+/// unsigned type will be sufficiently wide if it has at least one more value
+/// bit than the signed type.
+///
+/// Interestingly, the C++ language offers no direct way of doing what this
+/// function does, yet, this function is implemented in a way that makes no
+/// assumption about the underlying platform except what is guaranteed by C++11.
+///
+/// \tparam From The unsigned type used to store the two's complement
+/// representation.
+///
+/// \tparam To A signed or unsigned integer type.
+template <class To, class From>
+To from_twos_compl(From twos_compl) noexcept;
+
+
+// Implementation:
+
+template <class T>
+inline typename Promote<T>::type promote(T value) noexcept
+{
+    typedef typename Promote<T>::type promoted_type;
+    promoted_type value_2 = promoted_type(value);
+    return value_2;
+}
+
+} // namespace util
+
+namespace _impl {
+
+template <class T, bool is_signed>
+struct IsNegative {
+    static bool test(T value) noexcept
+    {
+        return value < 0;
+    }
+};
+template <class T>
+struct IsNegative<T, false> {
+    static bool test(T) noexcept
+    {
+        return false;
+    }
+};
+
+template <class To>
+struct CastToUnsigned {
+    template <class From>
+    static To cast(From value) noexcept
+    {
+        return To(value);
+    }
+};
+template <>
+struct CastToUnsigned<bool> {
+    template <class From>
+    static bool cast(From value) noexcept
+    {
+        return bool(unsigned(value) & 1);
+    }
+};
+
+template <class L, class R, bool l_signed, bool r_signed>
+struct SafeIntBinopsImpl {
+};
+
+// (unsigned, unsigned) (all size combinations)
+//
+// This implementation utilizes the fact that overflow in unsigned
+// arithmetic is guaranteed to be handled by reduction modulo 2**N
+// where N is the number of bits in the unsigned type. The purpose of
+// the bitwise 'and' with lim_l::max() is to make a cast to bool
+// behave the same way as casts to other unsigned integer types.
+// Finally, this implementation uses the fact that if modular addition
+// overflows, then the result must be a value that is less than both
+// operands. Also, if modular subtraction overflows, then the result
+// must be a value that is greater than the first operand.
+template <class L, class R>
+struct SafeIntBinopsImpl<L, R, false, false> {
+    typedef std::numeric_limits<L> lim_l;
+    typedef std::numeric_limits<R> lim_r;
+    static const int needed_bits_l = lim_l::digits;
+    static const int needed_bits_r = lim_r::digits;
+    static const int needed_bits = needed_bits_l >= needed_bits_r ? needed_bits_l : needed_bits_r;
+    typedef typename util::FastestUnsigned<needed_bits>::type common_unsigned;
+    static bool equal(L l, R r) noexcept
+    {
+        return common_unsigned(l) == common_unsigned(r);
+    }
+    static bool less(L l, R r) noexcept
+    {
+        return common_unsigned(l) < common_unsigned(r);
+    }
+    static bool add(L& lval, R rval) noexcept
+    {
+        L lval_2 = util::cast_to_unsigned<L>(lval + rval);
+        bool overflow = common_unsigned(lval_2) < common_unsigned(rval);
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = lval_2;
+        return false;
+    }
+    static bool sub(L& lval, R rval) noexcept
+    {
+        common_unsigned lval_2 = common_unsigned(lval) - common_unsigned(rval);
+        bool overflow = lval_2 > common_unsigned(lval);
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = util::cast_to_unsigned<L>(lval_2);
+        return false;
+    }
+};
+
+// (unsigned, signed) (all size combinations)
+template <class L, class R>
+struct SafeIntBinopsImpl<L, R, false, true> {
+    typedef std::numeric_limits<L> lim_l;
+    typedef std::numeric_limits<R> lim_r;
+    static const int needed_bits_l = lim_l::digits;
+    static const int needed_bits_r = lim_r::digits + 1;
+    static const int needed_bits = needed_bits_l >= needed_bits_r ? needed_bits_l : needed_bits_r;
+    typedef typename util::FastestUnsigned<needed_bits>::type common_unsigned;
+    typedef std::numeric_limits<common_unsigned> lim_cu;
+    static bool equal(L l, R r) noexcept
+    {
+        return (lim_l::digits > lim_r::digits) ? r >= 0 && l == util::cast_to_unsigned<L>(r) : R(l) == r;
+    }
+    static bool less(L l, R r) noexcept
+    {
+        return (lim_l::digits > lim_r::digits) ? r >= 0 && l < util::cast_to_unsigned<L>(r) : R(l) < r;
+    }
+    static bool add(L& lval, R rval) noexcept
+    {
+        common_unsigned lval_2 = lval + common_unsigned(rval);
+        bool overflow;
+        if (lim_l::digits < lim_cu::digits) {
+            overflow = common_unsigned(lval_2) > common_unsigned(lim_l::max());
+        }
+        else {
+            overflow = (lval_2 < common_unsigned(lval)) == (rval >= 0);
+        }
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = util::cast_to_unsigned<L>(lval_2);
+        return false;
+    }
+    static bool sub(L& lval, R rval) noexcept
+    {
+        common_unsigned lval_2 = lval - common_unsigned(rval);
+        bool overflow;
+        if (lim_l::digits < lim_cu::digits) {
+            overflow = common_unsigned(lval_2) > common_unsigned(lim_l::max());
+        }
+        else {
+            overflow = (common_unsigned(lval_2) > common_unsigned(lval)) == (rval >= 0);
+        }
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = util::cast_to_unsigned<L>(lval_2);
+        return false;
+    }
+};
+
+// (signed, unsigned) (all size combinations)
+template <class L, class R>
+struct SafeIntBinopsImpl<L, R, true, false> {
+    typedef std::numeric_limits<L> lim_l;
+    typedef std::numeric_limits<R> lim_r;
+    static const int needed_bits_l = lim_l::digits + 1;
+    static const int needed_bits_r = lim_r::digits;
+    static const int needed_bits = needed_bits_l >= needed_bits_r ? needed_bits_l : needed_bits_r;
+    typedef typename util::FastestUnsigned<needed_bits>::type common_unsigned;
+    static bool equal(L l, R r) noexcept
+    {
+        return (lim_l::digits < lim_r::digits) ? l >= 0 && util::cast_to_unsigned<R>(l) == r : l == L(r);
+    }
+    static bool less(L l, R r) noexcept
+    {
+        return (lim_l::digits < lim_r::digits) ? l < 0 || util::cast_to_unsigned<R>(l) < r : l < L(r);
+    }
+    static bool add(L& lval, R rval) noexcept
+    {
+        common_unsigned max_add = common_unsigned(lim_l::max()) - common_unsigned(lval);
+        bool overflow = common_unsigned(rval) > max_add;
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = util::from_twos_compl<L>(common_unsigned(lval) + rval);
+        return false;
+    }
+    static bool sub(L& lval, R rval) noexcept
+    {
+        common_unsigned max_sub = common_unsigned(lval) - common_unsigned(lim_l::min());
+        bool overflow = common_unsigned(rval) > max_sub;
+        if (REALM_UNLIKELY(overflow))
+            return true;
+        lval = util::from_twos_compl<L>(common_unsigned(lval) - rval);
+        return false;
+    }
+};
+
+// (signed, signed) (all size combinations)
+template <class L, class R>
+struct SafeIntBinopsImpl<L, R, true, true> {
+    typedef std::numeric_limits<L> lim_l;
+    static bool equal(L l, R r) noexcept
+    {
+        return l == r;
+    }
+    static bool less(L l, R r) noexcept
+    {
+        return l < r;
+    }
+    static bool add(L& lval, R rval) noexcept
+    {
+        // Note that both subtractions below occur in a signed type
+        // that is at least as wide as both of the two types. Note
+        // also that any signed type guarantees that there is no
+        // overflow when subtracting two negative values or two
+        // non-negative value. See C99 (adopted as subset of C++11)
+        // section 6.2.6.2 "Integer types" paragraph 2.
+        if (rval < 0) {
+            if (REALM_UNLIKELY(lval < lim_l::min() - rval))
+                return true;
+        }
+        else {
+            if (REALM_UNLIKELY(lval > lim_l::max() - rval))
+                return true;
+        }
+        // The following statement has exactly the same effect as
+        // `lval += rval`.
+        lval = L(lval + rval);
+        return false;
+    }
+    static bool sub(L& lval, R rval) noexcept
+    {
+        // Note that both subtractions below occur in a signed type
+        // that is at least as wide as both of the two types. Note
+        // also that there can be no overflow when adding a negative
+        // value to a non-negative value, or when adding a
+        // non-negative value to a negative one.
+        if (rval < 0) {
+            if (REALM_UNLIKELY(lval > lim_l::max() + rval))
+                return true;
+        }
+        else {
+            if (REALM_UNLIKELY(lval < lim_l::min() + rval))
+                return true;
+        }
+        // The following statement has exactly the same effect as
+        // `lval += rval`.
+        lval = L(lval - rval);
+        return false;
+    }
+};
+
+template <class L, class R>
+struct SafeIntBinops : SafeIntBinopsImpl<L, R, std::numeric_limits<L>::is_signed, std::numeric_limits<R>::is_signed> {
+    typedef std::numeric_limits<L> lim_l;
+    typedef std::numeric_limits<R> lim_r;
+    static_assert(lim_l::is_specialized && lim_r::is_specialized,
+                  "std::numeric_limits<> must be specialized for both types");
+    static_assert(lim_l::is_integer && lim_r::is_integer, "Both types must be integers");
+};
+
+} // namespace _impl
+
+namespace util {
+
+template <class T>
+inline bool is_negative(T value) noexcept
+{
+    return _impl::IsNegative<T, std::numeric_limits<T>::is_signed>::test(value);
+}
+
+template <class To, class From>
+inline To cast_to_unsigned(From value) noexcept
+{
+    return _impl::CastToUnsigned<To>::cast(value);
+}
+
+template <class A, class B>
+inline bool int_equal_to(A a, B b) noexcept
+{
+    return _impl::SafeIntBinops<A, B>::equal(a, b);
+}
+
+template <class A, class B>
+inline bool int_not_equal_to(A a, B b) noexcept
+{
+    return !_impl::SafeIntBinops<A, B>::equal(a, b);
+}
+
+template <class A, class B>
+inline bool int_less_than(A a, B b) noexcept
+{
+    return _impl::SafeIntBinops<A, B>::less(a, b);
+}
+
+template <class A, class B>
+inline bool int_less_than_or_equal(A a, B b) noexcept
+{
+    return !_impl::SafeIntBinops<B, A>::less(b, a); // Not greater than
+}
+
+template <class A, class B>
+inline bool int_greater_than(A a, B b) noexcept
+{
+    return _impl::SafeIntBinops<B, A>::less(b, a);
+}
+
+template <class A, class B>
+inline bool int_greater_than_or_equal(A a, B b) noexcept
+{
+    return !_impl::SafeIntBinops<A, B>::less(a, b); // Not less than
+}
+
+template <class L, class R>
+inline bool int_add_with_overflow_detect(L& lval, R rval) noexcept
+{
+    return _impl::SafeIntBinops<L, R>::add(lval, rval);
+}
+
+template <class L, class R>
+inline bool int_subtract_with_overflow_detect(L& lval, R rval) noexcept
+{
+    return _impl::SafeIntBinops<L, R>::sub(lval, rval);
+}
+
+template <class L, class R>
+inline bool int_multiply_with_overflow_detect(L& lval, R rval) noexcept
+{
+    // FIXME: Check if the following optimizes better (if it works at all):
+    // L lval_2 = L(lval * rval);
+    // bool overflow  =  rval != 0  &&  (lval_2 / rval) != lval;
+    typedef std::numeric_limits<L> lim_l;
+    typedef std::numeric_limits<R> lim_r;
+    static_assert(lim_l::is_specialized && lim_r::is_specialized,
+                  "std::numeric_limits<> must be specialized for both types");
+    static_assert(lim_l::is_integer && lim_r::is_integer, "Both types must be integers");
+    REALM_ASSERT(int_greater_than_or_equal(lval, 0));
+    REALM_ASSERT(int_greater_than(rval, 0));
+    if (int_less_than(lim_l::max() / rval, lval))
+        return true;
+    lval = L(lval * rval);
+    return false;
+}
+
+template <class T>
+inline bool int_shift_left_with_overflow_detect(T& lval, int i) noexcept
+{
+    typedef std::numeric_limits<T> lim;
+    static_assert(lim::is_specialized, "std::numeric_limits<> must be specialized for T");
+    static_assert(lim::is_integer, "T must be an integer type");
+    REALM_ASSERT(int_greater_than_or_equal(lval, 0));
+    if ((lim::max() >> i) < lval)
+        return true;
+    lval <<= i;
+    return false;
+}
+
+template <class To, class From>
+inline bool int_cast_has_overflow(From from) noexcept
+{
+    typedef std::numeric_limits<To> lim_to;
+    return int_less_than(from, lim_to::min()) || int_less_than(lim_to::max(), from);
+}
+
+template <class To, class From>
+inline bool int_cast_with_overflow_detect(From from, To& to) noexcept
+{
+    if (REALM_LIKELY(!int_cast_has_overflow<To>(from))) {
+        to = To(from);
+        return false;
+    }
+    return true;
+}
+
+template <class To, class From>
+inline To from_twos_compl(From twos_compl) noexcept
+{
+    typedef std::numeric_limits<From> lim_f;
+    typedef std::numeric_limits<To> lim_t;
+    static_assert(lim_f::is_specialized && lim_t::is_specialized,
+                  "std::numeric_limits<> must be specialized for both types");
+    static_assert(lim_f::is_integer && lim_t::is_integer, "Both types must be integers");
+    static_assert(!lim_f::is_signed, "`From` must be unsigned");
+    To native;
+    int sign_bit_pos = lim_f::digits - 1;
+    From sign_bit = From(1) << sign_bit_pos;
+    bool non_negative = !lim_t::is_signed || (twos_compl & sign_bit) == 0;
+    if (non_negative) {
+        // Non-negative value
+        native = To(twos_compl);
+    }
+    else {
+        // Negative value
+        native = To(-1 - To(From(-1) - twos_compl));
+    }
+    return native;
+}
+
+
+} // namespace util
+} // namespace realm
+
+#endif // REALM_UTIL_SAFE_INT_OPS_HPP