Skip to content

Commit a77eb55

Browse files
committed
fix: review comments
1 parent fe764af commit a77eb55

File tree

6 files changed

+74
-83
lines changed

6 files changed

+74
-83
lines changed

LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,11 @@ License: https://www.apache.org/licenses/LICENSE-2.0
256256

257257
--------------------------------------------------------------------------------
258258

259-
The file src/iceberg/expression/decimal.h contains code adapted from
259+
The file src/iceberg/util/decimal.h contains code adapted from
260260

261261
https://github.com/apache/arrow/blob/main/cpp/src/arrow/util/decimal.h
262262

263-
The file src/iceberg/expression/decimal.cc contains code adapted from
263+
The file src/iceberg/util/decimal.cc contains code adapted from
264264

265265
https://github.com/apache/arrow/blob/main/cpp/src/arrow/util/decimal.cc
266266

src/iceberg/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ set(ICEBERG_INCLUDES "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>"
2020
set(ICEBERG_SOURCES
2121
arrow_c_data_internal.cc
2222
catalog/in_memory_catalog.cc
23-
expression/decimal.cc
23+
util/decimal.cc
2424
expression/expression.cc
2525
expression/literal.cc
2626
file_reader.cc
@@ -48,6 +48,7 @@ set(ICEBERG_SOURCES
4848
manifest_reader.cc
4949
manifest_reader_internal.cc
5050
arrow_c_data_guard_internal.cc
51+
util/decimal.cc
5152
util/murmurhash3_internal.cc
5253
util/timepoint.cc
5354
util/gzip_internal.cc)

src/iceberg/expression/decimal.cc renamed to src/iceberg/util/decimal.cc

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
* under the License.
1818
*/
1919

20-
/// \file iceberg/expression/decimal.cc
20+
/// \file iceberg/util/decimal.cc
2121
/// \brief 128-bit fixed-point decimal numbers.
2222
/// Adapted from Apache Arrow with only Decimal128 support.
2323
/// https://github.com/apache/arrow/blob/main/cpp/src/arrow/util/decimal.cc
2424

25-
#include "iceberg/expression/decimal.h"
25+
#include "iceberg/util/decimal.h"
2626

2727
#include <algorithm>
2828
#include <array>
@@ -44,6 +44,7 @@
4444
#include <string_view>
4545

4646
#include "iceberg/result.h"
47+
#include "iceberg/util/int128.h"
4748
#include "iceberg/util/macros.h"
4849

4950
namespace iceberg {
@@ -314,7 +315,7 @@ static inline Status DecimalDivide(const Decimal& dividend, const Decimal& divis
314315
uint32_t prev = dividend_array[i];
315316
dividend_array[i] -= static_cast<uint32_t>(mult);
316317

317-
// if guess was too big, we add back divisor
318+
// if guess was too big, we add back divisor
318319
if (dividend_array[i] > prev) {
319320
guess--;
320321
uint32_t carry = 0;
@@ -1232,11 +1233,12 @@ static inline uint64_t UInt64FromBigEndian(const uint8_t* bytes, int32_t length)
12321233
// and doing the conversion in 16, 32 parts, which could
12331234
// possibly create unaligned memory access on certain platforms
12341235
memcpy(reinterpret_cast<uint8_t*>(&result) + 8 - length, bytes, length);
1235-
#if ICEBERG_LITTLE_ENDIAN
1236-
return std::byteswap(result);
1237-
#else
1238-
return result;
1239-
#endif
1236+
1237+
if constexpr (std::endian::native == std::endian::little) {
1238+
return std::byteswap(result);
1239+
} else {
1240+
return result;
1241+
}
12401242
}
12411243

12421244
static bool RescaleWouldCauseDataLoss(const Decimal& value, int32_t delta_scale,
@@ -1420,20 +1422,4 @@ ICEBERG_EXPORT Decimal operator%(const Decimal& lhs, const Decimal& rhs) {
14201422
return lhs.Divide(rhs).value().second;
14211423
}
14221424

1423-
ICEBERG_EXPORT bool operator<(const Decimal& lhs, const Decimal& rhs) {
1424-
return (lhs.high() < rhs.high()) || (lhs.high() == rhs.high() && lhs.low() < rhs.low());
1425-
}
1426-
1427-
ICEBERG_EXPORT bool operator<=(const Decimal& lhs, const Decimal& rhs) {
1428-
return !operator>(lhs, rhs);
1429-
}
1430-
1431-
ICEBERG_EXPORT bool operator>(const Decimal& lhs, const Decimal& rhs) {
1432-
return operator<(rhs, lhs);
1433-
}
1434-
1435-
ICEBERG_EXPORT bool operator>=(const Decimal& lhs, const Decimal& rhs) {
1436-
return !operator<(lhs, rhs);
1437-
}
1438-
14391425
} // namespace iceberg

src/iceberg/expression/decimal.h renamed to src/iceberg/util/decimal.h

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,24 @@
1919

2020
#pragma once
2121

22-
/// \file iceberg/expression/decimal.h
22+
/// \file iceberg/util/decimal.h
2323
/// \brief 128-bit fixed-point decimal numbers.
2424
/// Adapted from Apache Arrow with only Decimal128 support.
2525
/// https://github.com/apache/arrow/blob/main/cpp/src/arrow/util/decimal.h
2626

2727
#include <array>
28+
#include <bit>
2829
#include <cstdint>
2930
#include <iosfwd>
3031
#include <string>
3132
#include <string_view>
3233
#include <type_traits>
3334

35+
#include <iceberg/type.h>
36+
3437
#include "iceberg/iceberg_export.h"
3538
#include "iceberg/result.h"
3639
#include "iceberg/util/macros.h"
37-
#include "iceberg/util/port.h"
3840

3941
namespace iceberg {
4042

@@ -60,24 +62,24 @@ class ICEBERG_EXPORT Decimal {
6062
constexpr Decimal(T value) noexcept // NOLINT
6163
{
6264
if (value < T{}) {
63-
data_[kHighIndex] = ~static_cast<uint64_t>(0);
65+
data_[highIndex()] = ~static_cast<uint64_t>(0);
6466
} else {
65-
data_[kHighIndex] = 0;
67+
data_[highIndex()] = 0;
6668
}
67-
data_[kLowIndex] = static_cast<uint64_t>(value);
69+
data_[lowIndex()] = static_cast<uint64_t>(value);
6870
}
6971

7072
/// \brief Parse a Decimal from a string representation.
7173
explicit Decimal(std::string_view str);
7274

73-
/// \brief Create a Decimal from two 64-bit integers.
74-
#if ICEBERG_LITTLE_ENDIAN
75-
constexpr Decimal(int64_t high, uint64_t low) noexcept
76-
: data_{low, static_cast<uint64_t>(high)} {}
77-
#else
78-
constexpr Decimal(int64_t high, uint64_t low) noexcept
79-
: data_{static_cast<uint64_t>(high), low} {}
80-
#endif
75+
/// \brief Create a Decimal from two 64-bit integers.
76+
constexpr Decimal(int64_t high, uint64_t low) noexcept {
77+
if constexpr (std::endian::native == std::endian::little) {
78+
data_ = {low, static_cast<uint64_t>(high)};
79+
} else {
80+
data_ = {static_cast<uint64_t>(high), low};
81+
}
82+
}
8183

8284
/// \brief Negate the current Decimal value (in place)
8385
Decimal& Negate();
@@ -139,10 +141,10 @@ class ICEBERG_EXPORT Decimal {
139141
}
140142

141143
/// \brief Get the high bits of the two's complement representation of the number.
142-
constexpr int64_t high() const { return static_cast<int64_t>(data_[kHighIndex]); }
144+
constexpr int64_t high() const { return static_cast<int64_t>(data_[highIndex()]); }
143145

144146
/// \brief Get the low bits of the two's complement representation of the number.
145-
constexpr uint64_t low() const { return data_[kLowIndex]; }
147+
constexpr uint64_t low() const { return data_[lowIndex()]; }
146148

147149
/// \brief Convert the Decimal value to a base 10 decimal string with the given scale.
148150
/// \param scale The scale to use for the string representation.
@@ -178,6 +180,14 @@ class ICEBERG_EXPORT Decimal {
178180
/// Returns true if the number of significant digits is less or equal to `precision`.
179181
bool FitsInPrecision(int32_t precision) const;
180182

183+
/// \brief Spaceship operator for three-way comparison.
184+
std::strong_ordering operator<=>(const Decimal& other) const {
185+
if (high() != other.high()) {
186+
return high() <=> other.high();
187+
}
188+
return low() <=> other.low();
189+
}
190+
181191
/// \brief Convert to a signed integer
182192
template <typename T>
183193
requires std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t>
@@ -226,10 +236,10 @@ class ICEBERG_EXPORT Decimal {
226236
std::array<uint8_t, kByteWidth> ToBytes() const;
227237

228238
/// \brief Returns 1 if positive or zero, -1 if strictly negative.
229-
int64_t Sign() const { return 1 | (static_cast<int64_t>(data_[kHighIndex]) >> 63); }
239+
int64_t Sign() const { return 1 | (static_cast<int64_t>(data_[highIndex()]) >> 63); }
230240

231241
/// \brief Check if the Decimal value is negative.
232-
bool IsNegative() const { return static_cast<int64_t>(data_[kHighIndex]) < 0; }
242+
bool IsNegative() const { return static_cast<int64_t>(data_[highIndex()]) < 0; }
233243

234244
explicit operator bool() const { return data_ != std::array<uint64_t, 2>{0, 0}; }
235245

@@ -242,13 +252,21 @@ class ICEBERG_EXPORT Decimal {
242252
}
243253

244254
private:
245-
#if ICEBERG_LITTLE_ENDIAN
246-
static constexpr int32_t kHighIndex = 1;
247-
static constexpr int32_t kLowIndex = 0;
248-
#else
249-
static constexpr int32_t kHighIndex = 0;
250-
static constexpr int32_t kLowIndex = 1;
251-
#endif
255+
static constexpr int32_t highIndex() {
256+
if constexpr (std::endian::native == std::endian::little) {
257+
return 1;
258+
} else {
259+
return 0;
260+
}
261+
}
262+
263+
static constexpr int32_t lowIndex() {
264+
if constexpr (std::endian::native == std::endian::little) {
265+
return 0;
266+
} else {
267+
return 1;
268+
}
269+
}
252270

253271
std::array<uint64_t, 2> data_;
254272
};
@@ -259,12 +277,6 @@ ICEBERG_EXPORT std::ostream& operator<<(std::ostream& os, const Decimal& decimal
259277
ICEBERG_EXPORT Decimal operator-(const Decimal& operand);
260278
ICEBERG_EXPORT Decimal operator~(const Decimal& operand);
261279

262-
// Binary operators
263-
ICEBERG_EXPORT bool operator<=(const Decimal& lhs, const Decimal& rhs);
264-
ICEBERG_EXPORT bool operator<(const Decimal& lhs, const Decimal& rhs);
265-
ICEBERG_EXPORT bool operator>=(const Decimal& lhs, const Decimal& rhs);
266-
ICEBERG_EXPORT bool operator>(const Decimal& lhs, const Decimal& rhs);
267-
268280
ICEBERG_EXPORT Decimal operator+(const Decimal& lhs, const Decimal& rhs);
269281
ICEBERG_EXPORT Decimal operator-(const Decimal& lhs, const Decimal& rhs);
270282
ICEBERG_EXPORT Decimal operator*(const Decimal& lhs, const Decimal& rhs);

src/iceberg/util/port.h renamed to src/iceberg/util/int128.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,11 @@
1717
* under the License.
1818
*/
1919

20-
/// \file iceberg/util/port.h
21-
/// \brief Portability macros and definitions for Iceberg C++ library
20+
/// \file iceberg/util/int128.h
21+
/// \brief 128-bit integer type
2222

2323
#pragma once
2424

25-
#if defined(_WIN32) /* Windows is always little endian */ \
26-
|| defined(__LITTLE_ENDIAN__) || \
27-
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
28-
# define ICEBERG_LITTLE_ENDIAN 1
29-
#elif defined(__BIG_ENDIAN__) || \
30-
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
31-
# define ICEBERG_LITTLE_ENDIAN 0
32-
#else
33-
# error "Unsupported or unknown endianness"
34-
#endif
35-
3625
#if defined(_MSC_VER)
3726
# include <__msvc_int128.hpp>
3827
using int128_t = std::_Signed128;

test/decimal_test.cc

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
#include "iceberg/expression/decimal.h"
19+
#include "iceberg/util/decimal.h"
2020

2121
#include <algorithm>
2222
#include <array>
23+
#include <bit>
2324
#include <cmath>
2425
#include <cstdint>
2526
#include <vector>
@@ -28,7 +29,7 @@
2829
#include <gtest/gtest.h>
2930
#include <sys/types.h>
3031

31-
#include "iceberg/util/port.h"
32+
#include "iceberg/util/int128.h"
3233
#include "matchers.h"
3334

3435
namespace iceberg {
@@ -1030,9 +1031,10 @@ TEST(DecimalTest, FromBigEndian) {
10301031
Decimal value(start);
10311032
for (int ii = 0; ii < Decimal::kByteWidth; ++ii) {
10321033
auto native_endian = value.ToBytes();
1033-
#if ICEBERG_LITTLE_ENDIAN
1034-
std::ranges::reverse(native_endian);
1035-
#endif
1034+
if constexpr (std::endian::native == std::endian::little) {
1035+
// convert to big endian
1036+
std::ranges::reverse(native_endian);
1037+
}
10361038
// Limit the number of bytes we are passing to make
10371039
// sure that it works correctly. That's why all of the
10381040
// 'start' values don't have a 1 in the most significant
@@ -1047,10 +1049,11 @@ TEST(DecimalTest, FromBigEndian) {
10471049
auto negated = -value;
10481050
native_endian = negated.ToBytes();
10491051

1050-
#if ICEBERG_LITTLE_ENDIAN
1051-
// convert to big endian
1052-
std::ranges::reverse(native_endian);
1053-
#endif
1052+
if constexpr (std::endian::native == std::endian::little) {
1053+
// convert to big endian
1054+
std::ranges::reverse(native_endian);
1055+
}
1056+
10541057
result = Decimal::FromBigEndian(native_endian.data() + WidthMinusOne - ii, ii + 1);
10551058
ASSERT_THAT(result, IsOk());
10561059
const Decimal& negated_decimal = result.value();
@@ -1060,10 +1063,10 @@ TEST(DecimalTest, FromBigEndian) {
10601063
auto complement = ~value;
10611064
native_endian = complement.ToBytes();
10621065

1063-
#if ICEBERG_LITTLE_ENDIAN
1064-
// convert to big endian
1065-
std::ranges::reverse(native_endian);
1066-
#endif
1066+
if constexpr (std::endian::native == std::endian::little) {
1067+
// convert to big endian
1068+
std::ranges::reverse(native_endian);
1069+
}
10671070
result = Decimal::FromBigEndian(native_endian.data(), Decimal::kByteWidth);
10681071
ASSERT_THAT(result, IsOk());
10691072
const Decimal& complement_decimal = result.value();

0 commit comments

Comments
 (0)