1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#pragma once
19
20#include <array>
21#include <cstdint>
22#include <limits>
23#include <sstream>
24#include <string>
25#include <type_traits>
26
27#include "arrow/status.h"
28#include "arrow/util/basic_decimal.h"
29#include "arrow/util/string_view.h"
30
31namespace arrow {
32
33/// Represents a signed 128-bit integer in two's complement.
34/// Calculations wrap around and overflow is ignored.
35///
36/// For a discussion of the algorithms, look at Knuth's volume 2,
37/// Semi-numerical Algorithms section 4.3.1.
38///
39/// Adapted from the Apache ORC C++ implementation
40///
41/// The implementation is split into two parts :
42///
43/// 1. BasicDecimal128
44/// - can be safely compiled to IR without references to libstdc++.
45/// 2. Decimal128
46/// - has additional functionality on top of BasicDecimal128 to deal with
47/// strings and streams.
48class ARROW_EXPORT Decimal128 : public BasicDecimal128 {
49 public:
50 /// \cond FALSE
51 // (need to avoid a duplicate definition in Sphinx)
52 using BasicDecimal128::BasicDecimal128;
53 /// \endcond
54
55 /// \brief constructor creates a Decimal128 from a BasicDecimal128.
56 constexpr Decimal128(const BasicDecimal128& value) noexcept : BasicDecimal128(value) {}
57
58 /// \brief Parse the number from a base 10 string representation.
59 explicit Decimal128(const std::string& value);
60
61 /// \brief Empty constructor creates a Decimal128 with a value of 0.
62 // This is required on some older compilers.
63 constexpr Decimal128() noexcept : BasicDecimal128() {}
64
65 /// Divide this number by right and return the result.
66 ///
67 /// This operation is not destructive.
68 /// The answer rounds to zero. Signs work like:
69 /// 21 / 5 -> 4, 1
70 /// -21 / 5 -> -4, -1
71 /// 21 / -5 -> -4, 1
72 /// -21 / -5 -> 4, -1
73 /// \param[in] divisor the number to divide by
74 /// \param[out] result the quotient
75 /// \param[out] remainder the remainder after the division
76 Status Divide(const Decimal128& divisor, Decimal128* result,
77 Decimal128* remainder) const {
78 auto dstatus = BasicDecimal128::Divide(divisor, result, remainder);
79 return ToArrowStatus(dstatus);
80 }
81
82 /// \brief Convert the Decimal128 value to a base 10 decimal string with the given
83 /// scale.
84 std::string ToString(int32_t scale) const;
85
86 /// \brief Convert the value to an integer string
87 std::string ToIntegerString() const;
88
89 /// \brief Cast this value to an int64_t.
90 explicit operator int64_t() const;
91
92 /// \brief Convert a decimal string to a Decimal128 value, optionally including
93 /// precision and scale if they're passed in and not null.
94 static Status FromString(const util::string_view& s, Decimal128* out,
95 int32_t* precision = NULLPTR, int32_t* scale = NULLPTR);
96 static Status FromString(const std::string& s, Decimal128* out,
97 int32_t* precision = NULLPTR, int32_t* scale = NULLPTR);
98 static Status FromString(const char* s, Decimal128* out, int32_t* precision = NULLPTR,
99 int32_t* scale = NULLPTR);
100
101 /// \brief Convert from a big-endian byte representation. The length must be
102 /// between 1 and 16.
103 /// \return error status if the length is an invalid value
104 static Status FromBigEndian(const uint8_t* data, int32_t length, Decimal128* out);
105
106 /// \brief Convert Decimal128 from one scale to another
107 Status Rescale(int32_t original_scale, int32_t new_scale, Decimal128* out) const {
108 auto dstatus = BasicDecimal128::Rescale(original_scale, new_scale, out);
109 return ToArrowStatus(dstatus);
110 }
111
112 /// \brief Convert to a signed integer
113 template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>>
114 Status ToInteger(T* out) const {
115 constexpr auto min_value = std::numeric_limits<T>::min();
116 constexpr auto max_value = std::numeric_limits<T>::max();
117 const auto& self = *this;
118 if (self < min_value || self > max_value) {
119 return Status::Invalid("Invalid cast from Decimal128 to ", sizeof(T),
120 " byte integer");
121 }
122 *out = static_cast<T>(low_bits());
123 return Status::OK();
124 }
125
126 private:
127 /// Converts internal error code to Status
128 Status ToArrowStatus(DecimalStatus dstatus) const;
129};
130
131} // namespace arrow
132