You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by we...@apache.org on 2018/08/06 19:40:19 UTC

[arrow] 04/15: ARROW-2480: [C++] Enable casting the value of a decimal to int32_t or int64_t

This is an automated email from the ASF dual-hosted git repository.

wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git

commit 495bf36bedc8614dd49e309760b66f912987c800
Author: Antoine Pitrou <an...@python.org>
AuthorDate: Sat Aug 4 18:37:08 2018 -0400

    ARROW-2480: [C++] Enable casting the value of a decimal to int32_t or int64_t
    
    Author: Antoine Pitrou <an...@python.org>
    Author: Phillip Cloud <cp...@gmail.com>
    
    Closes #1917 from cpcloud/ARROW-2480 and squashes the following commits:
    
    456624e4 <Antoine Pitrou> Try to fix other compile error
    d9c2955a <Antoine Pitrou> Try to fix gcc 4.8 failure
    609efaec <Phillip Cloud> ARROW-2480:  Enable casting the value of a decimal to int32_t or int64_t
---
 cpp/src/arrow/util/decimal-test.cc | 26 ++++++++++++++++++++++++++
 cpp/src/arrow/util/decimal.h       | 18 ++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/cpp/src/arrow/util/decimal-test.cc b/cpp/src/arrow/util/decimal-test.cc
index 0877617..61884a1 100644
--- a/cpp/src/arrow/util/decimal-test.cc
+++ b/cpp/src/arrow/util/decimal-test.cc
@@ -436,4 +436,30 @@ TEST(Decimal128Test, TestFromBigEndianBadLength) {
   ASSERT_RAISES(Invalid, Decimal128::FromBigEndian(0, 17, &out));
 }
 
+TEST(Decimal128Test, TestToInteger) {
+  Decimal128 value1("1234");
+  int32_t out1;
+
+  Decimal128 value2("-1234");
+  int64_t out2;
+
+  ASSERT_OK(value1.ToInteger(&out1));
+  ASSERT_EQ(1234, out1);
+
+  ASSERT_OK(value1.ToInteger(&out2));
+  ASSERT_EQ(1234, out2);
+
+  ASSERT_OK(value2.ToInteger(&out1));
+  ASSERT_EQ(-1234, out1);
+
+  ASSERT_OK(value2.ToInteger(&out2));
+  ASSERT_EQ(-1234, out2);
+
+  Decimal128 invalid_int32(static_cast<int64_t>(std::pow(2, 31)));
+  ASSERT_RAISES(Invalid, invalid_int32.ToInteger(&out1));
+
+  Decimal128 invalid_int64("12345678912345678901");
+  ASSERT_RAISES(Invalid, invalid_int64.ToInteger(&out2));
+}
+
 }  // namespace arrow
diff --git a/cpp/src/arrow/util/decimal.h b/cpp/src/arrow/util/decimal.h
index b3180cb..7280362 100644
--- a/cpp/src/arrow/util/decimal.h
+++ b/cpp/src/arrow/util/decimal.h
@@ -20,11 +20,14 @@
 
 #include <array>
 #include <cstdint>
+#include <limits>
+#include <sstream>
 #include <string>
 #include <type_traits>
 
 #include "arrow/status.h"
 #include "arrow/util/macros.h"
+#include "arrow/util/type_traits.h"
 #include "arrow/util/visibility.h"
 
 namespace arrow {
@@ -134,6 +137,21 @@ class ARROW_EXPORT Decimal128 {
   /// \brief Convert Decimal128 from one scale to another
   Status Rescale(int32_t original_scale, int32_t new_scale, Decimal128* out) const;
 
+  /// \brief Convert to a signed integer
+  template <typename T, typename = EnableIfIsOneOf<T, int32_t, int64_t>>
+  Status ToInteger(T* out) const {
+    constexpr auto min_value = std::numeric_limits<T>::min();
+    constexpr auto max_value = std::numeric_limits<T>::max();
+    const auto& self = *this;
+    if (self < min_value || self > max_value) {
+      std::stringstream buf;
+      buf << "Invalid cast from Decimal128 to " << sizeof(T) << " byte integer";
+      return Status::Invalid(buf.str());
+    }
+    *out = static_cast<T>(low_bits_);
+    return Status::OK();
+  }
+
  private:
   int64_t high_bits_;
   uint64_t low_bits_;