http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/util/CMakeLists.txt b/src/kudu/util/CMakeLists.txt
index b107b73..82a5a02 100644
--- a/src/kudu/util/CMakeLists.txt
+++ b/src/kudu/util/CMakeLists.txt
@@ -128,6 +128,7 @@ set(UTIL_SRCS
   cow_object.cc
   crc.cc
   debug-util.cc
+  decimal_util.cc
   debug/trace_event_impl.cc
   debug/trace_event_impl_constants.cc
   debug/trace_event_synthetic_delay.cc
@@ -339,6 +340,7 @@ ADD_KUDU_TEST(callback_bind-test)
 ADD_KUDU_TEST(countdown_latch-test)
 ADD_KUDU_TEST(crc-test RUN_SERIAL true) # has a benchmark
 ADD_KUDU_TEST(debug-util-test)
+ADD_KUDU_TEST(decimal_util-test)
 ADD_KUDU_TEST(easy_json-test)
 ADD_KUDU_TEST(env-test LABELS no_tsan)
 ADD_KUDU_TEST(env_util-test)

http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/decimal_util-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/decimal_util-test.cc 
b/src/kudu/util/decimal_util-test.cc
new file mode 100644
index 0000000..e8c9fc1
--- /dev/null
+++ b/src/kudu/util/decimal_util-test.cc
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "kudu/util/decimal_util.h"
+
+using std::string;
+
+namespace kudu {
+
+TEST(TestDecimalUtil, TestMaxUnscaledDecimal) {
+  ASSERT_EQ(9, MaxUnscaledDecimal(1));
+  ASSERT_EQ(99999, MaxUnscaledDecimal(5));
+  ASSERT_EQ(kMaxUnscaledDecimal32, MaxUnscaledDecimal(kMaxDecimal32Precision));
+  ASSERT_EQ(kMaxUnscaledDecimal64, MaxUnscaledDecimal(kMaxDecimal64Precision));
+  ASSERT_EQ(kMaxUnscaledDecimal128, 
MaxUnscaledDecimal(kMaxDecimal128Precision));
+}
+
+TEST(TestDecimalUtil, TestToString) {
+  ASSERT_EQ("999999999",
+            DecimalToString(kMaxUnscaledDecimal32, kDefaultDecimalScale));
+  ASSERT_EQ("0.999999999",
+            DecimalToString(kMaxUnscaledDecimal32, kMaxDecimal32Precision));
+  ASSERT_EQ("-999999999",
+            DecimalToString(kMinUnscaledDecimal32, kDefaultDecimalScale));
+  ASSERT_EQ("-0.999999999",
+            DecimalToString(kMinUnscaledDecimal32, kMaxDecimal32Precision));
+
+  ASSERT_EQ("999999999999999999",
+            DecimalToString(kMaxUnscaledDecimal64, kDefaultDecimalScale));
+  ASSERT_EQ("0.999999999999999999",
+            DecimalToString(kMaxUnscaledDecimal64, kMaxDecimal64Precision));
+  ASSERT_EQ("-999999999999999999",
+            DecimalToString(kMinUnscaledDecimal64, kDefaultDecimalScale));
+  ASSERT_EQ("-0.999999999999999999",
+            DecimalToString(kMinUnscaledDecimal64, kMaxDecimal64Precision));
+
+  ASSERT_EQ("99999999999999999999999999999999999999",
+            DecimalToString(kMaxUnscaledDecimal128, kDefaultDecimalScale));
+  ASSERT_EQ("0.99999999999999999999999999999999999999",
+            DecimalToString(kMaxUnscaledDecimal128, kMaxDecimal128Precision));
+  ASSERT_EQ("-99999999999999999999999999999999999999",
+            DecimalToString(kMinUnscaledDecimal128, kDefaultDecimalScale));
+  ASSERT_EQ("-0.99999999999999999999999999999999999999",
+            DecimalToString(kMinUnscaledDecimal128, kMaxDecimal128Precision));
+
+  ASSERT_EQ("0", DecimalToString(0, 0));
+  ASSERT_EQ("12345", DecimalToString(12345, 0));
+  ASSERT_EQ("-12345", DecimalToString(-12345, 0));
+  ASSERT_EQ("123.45", DecimalToString(12345, 2));
+  ASSERT_EQ("-123.45", DecimalToString(-12345, 2));
+  ASSERT_EQ("0.00012345", DecimalToString(12345, 8));
+  ASSERT_EQ("-0.00012345", DecimalToString(-12345, 8));
+}
+
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/decimal_util.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/decimal_util.cc b/src/kudu/util/decimal_util.cc
new file mode 100644
index 0000000..af81ae5
--- /dev/null
+++ b/src/kudu/util/decimal_util.cc
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+#include "kudu/util/decimal_util.h"
+
+#include <string>
+
+#include <glog/logging.h>
+
+namespace kudu {
+
+using std::string;
+
+// Workaround for an ASAN build issue documented here:
+// https://bugs.llvm.org/show_bug.cgi?id=16404
+__attribute__((no_sanitize("undefined")))
+int128_t MaxUnscaledDecimal(int8_t precision) {
+  DCHECK_GE(precision, kMinDecimalPrecision);
+  DCHECK_LE(precision, kMaxDecimalPrecision);
+  int128_t result = 1;
+  for (; precision > 0; precision--) {
+    result = result * 10;
+  }
+  return result - 1;
+}
+
+// Workaround for an ASAN build issue documented here:
+// https://bugs.llvm.org/show_bug.cgi?id=16404
+__attribute__((no_sanitize("undefined")))
+string DecimalToString(int128_t d, int8_t scale) {
+  // 38 digits, 1 extra leading zero, decimal point,
+  // and sign are good for 128-bit or smaller decimals.
+  char local[41];
+  char *p = local + sizeof(local);
+  int128_t n = d < 0? -d : d;
+  int position = 0;
+  while (n) {
+    // Print the decimal in the scale position.
+    // No decimal is output when scale is 0.
+    if (scale != 0 && position == scale) {
+      *--p = '.';
+    }
+    // Unroll the next digits.
+    *--p = '0' + n % 10;
+    n /= 10;
+    position++;
+  }
+  // True if the value is between 1 and -1.
+  bool fractional = position <= scale;
+  // Pad with zeros until the scale
+  while (position < scale) {
+    *--p = '0';
+    position++;
+  }
+  // Add leading "0.".
+  if (fractional) {
+    if (d != 0) {
+      *--p = '.';
+    }
+    *--p = '0';
+  }
+  // Add sign for negative values.
+  if (d < 0) {
+    *--p = '-';
+  }
+  return string(p, local + sizeof(local));
+}
+
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/decimal_util.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/decimal_util.h b/src/kudu/util/decimal_util.h
new file mode 100644
index 0000000..271bc0e
--- /dev/null
+++ b/src/kudu/util/decimal_util.h
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+#pragma once
+
+#include <stdint.h>
+#include <string>
+
+#include "kudu/util/int128.h"
+
+namespace kudu {
+  // Maximum precision and absolute value of a Decimal that can be stored
+  // in 4 bytes.
+  static const int8_t kMaxDecimal32Precision = 9;
+  static const int32_t kMaxUnscaledDecimal32 = 999999999; // 9 9's
+  static const int32_t kMinUnscaledDecimal32 = -kMaxUnscaledDecimal32; // 9 9's
+
+  // Maximum precision and absolute value of a valid Decimal can be
+  // stored in 8 bytes.
+  static const int8_t kMaxDecimal64Precision = 18;
+  static const int64_t kMaxUnscaledDecimal64 = 999999999999999999; // 18 9's
+  static const int64_t kMinUnscaledDecimal64 = -kMaxUnscaledDecimal64; // 18 
9's
+
+  // Maximum precision and absolute value of a valid Decimal can be
+  // stored in 16 bytes.
+  static const int8_t kMaxDecimal128Precision = 38;
+  // Hacky calculation because int128 literals are not supported.
+  static const int128_t kMaxUnscaledDecimal128 =
+      (((static_cast<int128_t>(999999999999999999) * 1000000000000000000) +
+          999999999999999999) * 100) + 99; // 38 9's
+  static const int128_t kMinUnscaledDecimal128 = -kMaxUnscaledDecimal128;
+
+  // Minimum and maximum precision for any Decimal.
+  static const int8_t kMinDecimalPrecision = 1;
+  static const int8_t kMaxDecimalPrecision = kMaxDecimal128Precision;
+  // Maximum absolute value for any Decimal.
+  static const int128_t kMaxUnscaledDecimal = kMaxUnscaledDecimal128;
+  static const int128_t kMinUnscaledDecimal = kMinUnscaledDecimal128;
+
+  // Minimum scale for any Decimal.
+  static const int8_t kMinDecimalScale = 0;
+  static const int8_t kDefaultDecimalScale = 0;
+  // The maximum scale is the Decimal's precision.
+
+  // Returns the maximum unscaled decimal value that can be stored
+  // based on the precision
+  int128_t MaxUnscaledDecimal(int8_t precision);
+
+  std::string DecimalToString(int128_t value, int8_t scale);
+
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/int128-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/int128-test.cc b/src/kudu/util/int128-test.cc
index 175c4e4..30b84f4 100644
--- a/src/kudu/util/int128-test.cc
+++ b/src/kudu/util/int128-test.cc
@@ -31,12 +31,10 @@ namespace kudu {
 
 TEST(TestInt128, TestOstreamSigned) {
   int128_t INTEGERS[] = {0, -1, 1, -1234567890,
-                         -12345678901011121314151617181920212223_i128,
                          INT64_MIN, UINT64_MAX,
                          INT128_MIN,
                          INT128_MAX};
   std::string STRINGS[] = {"0", "-1", "1", "-1234567890",
-                           "-12345678901011121314151617181920212223",
                            "-9223372036854775808", "18446744073709551615",
                            "-170141183460469231731687303715884105728",
                            "170141183460469231731687303715884105727"};
@@ -48,9 +46,9 @@ TEST(TestInt128, TestOstreamSigned) {
 }
 
 TEST(TestInt128, TestOstreamUnsigned) {
-  uint128_t INTEGERS[] = {0, 1, 1234567890, 
123456789101112131415161718192021222324_u128,
+  uint128_t INTEGERS[] = {0, 1, 1234567890,
                           UINT128_MIN, UINT128_MAX};
-  string STRINGS[] = {"0", "1", "1234567890", 
"123456789101112131415161718192021222324",
+  string STRINGS[] = {"0", "1", "1234567890",
                       "0", "340282366920938463463374607431768211455"};
   for (size_t i = 0; i < arraysize(INTEGERS); i++) {
     std::ostringstream ss;
@@ -67,25 +65,4 @@ TEST(TestInt128, TestCasting) {
   ASSERT_EQ(UINT128_MAX, castToMax);
 }
 
-TEST(TestInt128, TestSuffix) {
-  int128_t imax = 170141183460469231731687303715884105727_i128;
-  ASSERT_EQ(INT128_MAX, imax);
-
-  // Note: We can't represent the absolute minimum because numeric literals
-  // never represent negative numbers and the - operator is applied after
-  // the conversion to an int128_t.
-  int128_t imin = -170141183460469231731687303715884105727_i128;
-  ASSERT_EQ(INT128_MIN + 1, imin);
-
-  uint128_t umax = 340282366920938463463374607431768211455_u128;
-  ASSERT_EQ(UINT128_MAX, umax);
-
-  uint128_t umin = 0_u128;
-  ASSERT_EQ(UINT128_MIN, umin);
-
-  // The values below will fail to compile
-  // 170141183460469231731687303715884105728_i128; // Too large int128_t
-  // 3340282366920938463463374607431768211456_u128; // Too large uint128_t
-}
-
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7b6cc845/src/kudu/util/int128.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/int128.h b/src/kudu/util/int128.h
index e78e450..96e51a8 100644
--- a/src/kudu/util/int128.h
+++ b/src/kudu/util/int128.h
@@ -22,8 +22,6 @@
 
 #include <iostream>
 
-#include "kudu/gutil/mathlimits.h"
-
 namespace kudu {
 
 typedef unsigned __int128 uint128_t;
@@ -31,82 +29,10 @@ typedef signed __int128 int128_t;
 
 // Note: We don't use numeric_limits because it can give incorrect
 // values for __int128 and unsigned __int128.
-static const uint128_t UINT128_MIN = MathLimits<uint128_t>::kMin;
-static const uint128_t UINT128_MAX = MathLimits<uint128_t>::kMax;
-static const int128_t INT128_MIN = MathLimits<int128_t>::kMin;
-static const int128_t INT128_MAX = MathLimits<int128_t>::kMax;
-
-namespace int128Suffix {
-
-// Convert the characters 0 through 9 to their int value.
-constexpr uint128_t CharValue(char c) {
-  return c - '0';
-}
-
-// Terminate the recursion.
-template <uint128_t VALUE>
-constexpr uint128_t ValidateU128Helper() {
-  return true;
-}
-
-// Recurse the literal from left to right and validate the input.
-// Return true if the input is valid.
-template <uint128_t VALUE, char C, char... CS>
-constexpr bool ValidateU128Helper() {
-  return (VALUE <= UINT128_MAX / 10) &&
-         VALUE * 10 <= UINT128_MAX - CharValue(C) &&
-         ValidateU128Helper<VALUE * 10 + CharValue(C), CS...>();
-}
-
-template <char... CS>
-constexpr bool ValidateU128() {
-  return ValidateU128Helper<0, CS...>();
-}
-
-// Terminate the recursion.
-template <uint128_t VALUE>
-constexpr uint128_t MakeU128Helper() {
-  return VALUE;
-}
-
-// Recurse the literal from left to right calculating the resulting value.
-// C is the current left most character, CS is the rest.
-template <uint128_t VALUE, char C, char... CS>
-constexpr uint128_t MakeU128Helper() {
-  return MakeU128Helper<VALUE * 10 + CharValue(C), CS...>();
-}
-
-template <char... CS>
-constexpr uint128_t MakeU128() {
-  return MakeU128Helper<0, CS...>();
-}
-
-template <char... CS>
-constexpr bool ValidateI128() {
-  return ValidateU128Helper<0, CS...>() && MakeU128<CS...>() <= INT128_MAX;
-}
-
-}  // namespace int128Suffix
-
-// User-defined literal "_u128" to support basic integer constants
-// for uint128_t until officially supported by compilers.
-template <char... CS>
-constexpr uint128_t operator"" _u128() {
-  static_assert(int128Suffix::ValidateU128<CS...>(),
-                "integer literal is too large to be represented in "
-                    "uint128_t integer type");
-  return int128Suffix::MakeU128<CS...>();
-}
-
-// User-defined literal "_u128" to support basic integer constants
-// for int128_t until officially supported by compilers.
-template <char... CS>
-constexpr int128_t operator"" _i128() {
-  static_assert(int128Suffix::ValidateI128<CS...>(),
-                "integer literal is too large to be represented in "
-                    "int128_t integer type");
-  return static_cast<int128_t>(int128Suffix::MakeU128<CS...>());
-}
+static const uint128_t UINT128_MIN = (uint128_t) 0;
+static const uint128_t UINT128_MAX = ((uint128_t) -1);
+static const int128_t INT128_MAX = ((int128_t)(UINT128_MAX >> 1));
+static const int128_t INT128_MIN = (-INT128_MAX - 1);
 
 } // namespace kudu
 

Reply via email to