blob: 707e3e58066bec7db40b226205e67de4f0cd9ce7 [file]
/*
* 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 <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include "paimon/visibility.h"
namespace paimon {
class Bytes;
/// A data structure representing data of Decimal. It might be stored in a compact representation
/// (as a long value) if values are small enough.
class PAIMON_EXPORT Decimal {
public:
using int128_t = __int128_t;
using uint128_t = __uint128_t;
Decimal(int32_t precision, int32_t scale, int128_t value)
: precision_(precision), scale_(scale), value_(value) {}
/// Get the **precision** of this decimal.
///
/// The precision is the number of digits in the unscaled value.
int32_t Precision() const {
return precision_;
}
/// Get the **scale** of this decimal.
int32_t Scale() const {
return scale_;
}
/// Get the underlying int128_t value of this decimal.
int128_t Value() const {
return value_;
}
/// Get the low 64 bits of the decimal value.
uint64_t LowBits() const {
return static_cast<uint64_t>(value_ & 0xFFFFFFFFFFFFFFFF);
}
/// Get the high 64 bits of the decimal value.
uint64_t HighBits() const {
return static_cast<uint64_t>(value_ >> 64);
}
/// @return Whether the decimal value is small enough to be stored in a long.
bool IsCompact() const {
return precision_ <= MAX_COMPACT_PRECISION;
}
std::string ToString() const;
/// @return Whether the decimal value is small enough to be stored in a long.
static bool IsCompact(int32_t precision) {
return precision <= MAX_COMPACT_PRECISION;
}
/// Creates an instance of `Decimal` from an unscaled long value and the given precision and
/// scale.
static Decimal FromUnscaledLong(int64_t unscaled_long, int32_t precision, int32_t scale) {
return {precision, scale, unscaled_long};
}
/// @return A long describing the **unscaled value** of this decimal.
int64_t ToUnscaledLong() const {
int64_t ret = 0;
uint64_t low_bits = (value_ & 0xFFFFFFFFFFFFFFFF);
memcpy(&ret, &low_bits, sizeof(uint64_t));
return ret;
}
/// @return A byte array describing the **unscaled value** of this decimal.
std::vector<char> ToUnscaledBytes() const;
/// Creates an instance of `Decimal` from an unscaled byte array value and the given precision
/// and scale.
static Decimal FromUnscaledBytes(int32_t precision, int32_t scale, Bytes* bytes);
bool operator==(const Decimal& other) const {
if (this == &other) {
return true;
}
return CompareTo(other) == 0;
}
bool operator<(const Decimal& other) const {
if (this == &other) {
return false;
}
return CompareTo(other) < 0;
}
bool operator>(const Decimal& other) const {
if (this == &other) {
return false;
}
return CompareTo(other) > 0;
}
int32_t CompareTo(const Decimal& other) const;
static constexpr int32_t DEFAULT_PRECISION = 10;
static constexpr int32_t DEFAULT_SCALE = 0;
static constexpr int32_t MIN_PRECISION = 1;
static constexpr int32_t MAX_PRECISION = 38;
private:
static constexpr int32_t MAX_COMPACT_PRECISION = 18;
static const int128_t INT128_MAXIMUM_VALUE;
static const int128_t INT128_MINIMUM_VALUE;
static const int64_t POWERS_OF_TEN[MAX_COMPACT_PRECISION + 1];
static int32_t clz_u128(uint128_t u);
static int32_t count_leading_zero_bytes(uint128_t u);
static int32_t count_leading_all_ones_bytes(uint128_t u);
static int128_t DownScaleInt128(int128_t value, int32_t scale);
static int128_t ScaleInt128(int128_t value, int32_t scale, bool* overflow);
private:
int32_t precision_ = 0;
int32_t scale_ = 0;
int128_t value_ = 0;
};
} // namespace paimon