[Groonga-commit] groonga/grnxx at 415233e [master] Add operators to the new Int.

Back to archive index

susumu.yata null+****@clear*****
Thu Oct 23 21:11:34 JST 2014


susumu.yata	2014-10-23 21:11:34 +0900 (Thu, 23 Oct 2014)

  New Revision: 415233e3d6ff07905a60aa850b138ca76080b023
  https://github.com/groonga/grnxx/commit/415233e3d6ff07905a60aa850b138ca76080b023

  Message:
    Add operators to the new Int.

  Modified files:
    include/grnxx/new_types/int.hpp

  Modified: include/grnxx/new_types/int.hpp (+216 -3)
===================================================================
--- include/grnxx/new_types/int.hpp    2014-10-23 18:28:08 +0900 (fb0c658)
+++ include/grnxx/new_types/int.hpp    2014-10-23 21:11:34 +0900 (73a4030)
@@ -8,6 +8,7 @@
 
 namespace grnxx {
 
+// NOTE: This implementation assumes two's complement.
 class Int {
  public:
   Int() = default;
@@ -38,8 +39,12 @@ class Int {
   constexpr Int operator+() const {
     return *this;
   }
+  // NOTE: This implementation assumes that -na_value() returns na_value(),
+  //       although -na_value() in two's complement causes an overflow and
+  //       the behavior is undefined in C/C++.
+  //       If this assumption is wrong, N/A must be excluded.
   constexpr Int operator-() const {
-    return is_na() ? na() : Int(-value_);
+    return Int(-value_);
   }
   constexpr Int operator~() const {
     return is_na() ? na() : Int(~value_);
@@ -101,9 +106,73 @@ class Int {
     return *this;
   }
 
-  // TODO: Bitwise shift operators.
+  // -- Bitwise shift operators --
 
-  // TODO: Arithmetic operators.
+  constexpr Int operator<<(Int rhs) const {
+    return (is_na() || rhs.is_na() ||
+            (static_cast<uint64_t>(rhs.value_) >= 64)) ?
+           na() : Int(value_ << rhs.value_);
+  }
+  constexpr Int operator>>(Int rhs) const {
+    return (is_na() || rhs.is_na() ||
+            (static_cast<uint64_t>(rhs.value_) >= 64)) ?
+           na() : Int(value_ >> rhs.value_);
+  }
+
+  Int &operator<<=(Int rhs) & {
+    if (!is_na()) {
+      if (rhs.is_na() || (static_cast<uint64_t>(rhs.value_) >= 64)) {
+        value_ = na_value();
+      } else {
+        value_ <<= rhs.value_;
+      }
+    }
+    return *this;
+  }
+  Int &operator>>=(Int rhs) & {
+    if (!is_na()) {
+      if (rhs.is_na() || (static_cast<uint64_t>(rhs.value_) >= 64)) {
+        value_ = na_value();
+      } else {
+        value_ >>= rhs.value_;
+      }
+    }
+    return *this;
+  }
+
+  // -- Arithmetic operators --
+
+  // NOTE: C++11 does not allow `if` in constexpr function, but C++14 does.
+  Int operator+(Int rhs) const {
+    return add(*this, rhs);
+  }
+  Int operator-(Int rhs) const {
+    return subtract(*this, rhs);
+  }
+  Int operator*(Int rhs) const {
+    return multiply(*this, rhs);
+  };
+  Int operator/(Int rhs) const {
+    return (is_na() || rhs.is_na() || (rhs.value_ == 0)) ?
+           na() : Int(value_ / rhs.value_);
+  }
+
+  Int &operator+=(Int rhs) & {
+    return *this = operator+(rhs);
+  }
+  Int &operator-=(Int rhs) & {
+    return *this = operator-(rhs);
+  }
+  Int &operator*=(Int rhs) & {
+    return *this = operator*(rhs);
+  }
+  Int &operator/=(Int rhs) &{
+    if (!is_na()) {
+      value_ = (rhs.is_na() || (rhs.value_ == 0)) ?
+               na_value() : (value_ / rhs.value_);
+    }
+    return *this;
+  }
 
   // -- Comparison operators --
 
@@ -142,6 +211,150 @@ class Int {
 
  private:
   int64_t value_;
+
+#if defined(GRNXX_HAVE_X86_64)
+ #if defined(GRNXX_HAVE_GNUC)
+  static Int add(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    __asm__ ("ADD %1, %0;"
+             "JNO GRNXX_INT_ADD_OVERFLOW%=;"
+             "MOV %2, %0;"
+             "GRNXX_INT_ADD_OVERFLOW%=:"
+             : "+r" (lhs.value_)
+             : "r" (rhs.value_), "r" (na_value()));
+    return lhs;
+  }
+  static Int subtract(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    __asm__ ("SUB %1, %0;"
+             "JNO GRNXX_INT_SUBTRACT_OVERFLOW%=;"
+             "MOV %2, %0;"
+             "GRNXX_INT_SUBTRACT_OVERFLOW%=:"
+             : "+r" (lhs.value_)
+             : "r" (rhs.value_), "r" (na_value()));
+    return lhs;
+  }
+  static Int multiply(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    __asm__ ("IMUL %1, %0;"
+             "JNO GRNXX_INT_MULTIPLY_OVERFLOW%=;"
+             "MOV %2, %0;"
+             "GRNXX_INT_MULTIPLY_OVERFLOW%=:"
+             : "+r" (lhs.value_)
+             : "r" (rhs.value_), "r" (na_value()));
+    return lhs;
+  }
+ #else  // !defined(GRNXX_HAVE_GNUC)
+  // TODO: Use assmbly for VC++.
+ #endif  // defined(GRNXX_HAVE_GNUC), etc.
+#elif defined(GRNXX_HAVE_WRAP_AROUND)  // !defined(GRNXX_HAVE_X86_64)
+  // NOTE: These implementations assume silent two's complement wrap-around,
+  //       although a signed integer overflow causes undefined behavior in
+  //       C/C++.
+  static Int add(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    int64_t result_value = lhs.value_ + rhs.value_;
+    lhs.value_ ^= result_value;
+    rhs.value_ ^= result_value;
+    if (static_cast<uint64_t>(lhs.value_ & rhs.value_) >> 63) {
+      return na();
+    }
+    return Int(result_value);
+  }
+  static Int subtract(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    int64_t result_value = lhs.value_ - rhs.value_;
+    lhs.value_ ^= result_value;
+    rhs.value_ ^= result_value;
+    if (static_cast<uint64_t>(lhs.value_ & rhs.value_) >> 63) {
+      return na();
+    }
+    return Int(result_value);
+  }
+  static Int multiply(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    if (rhs.value_ == 0) {
+      return Int(0);
+    }
+    int64_t result = lhs.value_ * rhs.value_;
+    if ((result / rhs.value_) != lhs.value_) {
+      return na();
+    }
+    return Int(result);
+  }
+#else  // !defined(GRNXX_HAVE_X86_64) && !defined(GRNXX_HAVE_WRAP_AROUND)
+  // NOTE: These implementations are portable but slow.
+  static Int add(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    if (lhs.value_ >= 0) {
+      if (rhs.value_ > (max_value() - lhs.value_)) {
+        return na();
+      }
+    } else {
+      if (rhs.value_ < (min_value() - lhs.value_)) {
+        return na();
+      }
+    }
+    return Int(lhs.value_ + rhs.value_);
+  }
+  static Int subtract(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    if (rhs.value_ >= 0) {
+      if (lhs.value_ < (min_value() + rhs.value_)) {
+        return na();
+      }
+    } else {
+      if (lhs.value_ > (max_value() + rhs.value_)) {
+        return na();
+      }
+    }
+    return Int(lhs.value_ - rhs.value_);
+  }
+  static Int multiply(Int lhs, Int rhs) {
+    if (lhs.is_na() || rhs.is_na()) {
+      return na();
+    }
+    if (rhs.value_ == 0) {
+      return Int(0);
+    }
+    if (lhs.value_ >= 0) {
+      if (rhs.value_ > 0) {
+        if (lhs.value_ > (max_value() / rhs.value_)) {
+          return na();
+        }
+      } else {
+        if (lhs.value_ > (min_value() / rhs.value_)) {
+          return na();
+        }
+      }
+    } else if (rhs.value_ > 0) {
+      if (lhs.value_ < (min_value() / rhs.value_)) {
+        return na();
+      }
+    } else {
+      if (lhs.value_ < (max_value() / rhs.value_)) {
+        return na();
+      }
+    }
+    return Int(lhs.value_ * rhs.value_);
+  }
+#endif  // defined(GRNXX_HAVE_X86_64), etc.
 };
 
 }  // namespace grnxx
-------------- next part --------------
HTML����������������������������...
下载 



More information about the Groonga-commit mailing list
Back to archive index