This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-nanoarrow.git
The following commit(s) were added to refs/heads/main by this push:
new 4a62bab feat: Add Decimal Get/Set utilities (#180)
4a62bab is described below
commit 4a62bab9ab47d4d159e9405bec62ffb41485acba
Author: Dewey Dunnington <[email protected]>
AuthorDate: Fri Apr 14 13:51:36 2023 -0400
feat: Add Decimal Get/Set utilities (#180)
Closes #170.
This is not designed to be a fully-featured performant decimal math
library, but is designed to help with byte shuffling and provide enough
support that users can write tests for decimal arrays (e.g., by
providing integer getters and setters for numbers that fit within the
int64 range).
Adds a `struct ArrowDecimal` and utility functions:
```c
static inline void ArrowDecimalInit(struct ArrowDecimal* decimal, int32_t
bitwidth,
int32_t precision, int32_t scale);
static inline int64_t ArrowDecimalGetIntUnsafe(struct ArrowDecimal*
decimal);
static inline void ArrowDecimalGetBytes(struct ArrowDecimal* decimal,
uint8_t* out);
static inline int64_t ArrowDecimalSign(struct ArrowDecimal* decimal);
static inline void ArrowDecimalSetInt(struct ArrowDecimal* decimal, int64_t
value);
static inline void ArrowDecimalSetBytes(struct ArrowDecimal* decimal,
const uint8_t* value);
```
...and adds a "getter" and an "appender":
```c
static inline ArrowErrorCode ArrowArrayAppendDecimal(struct ArrowArray*
array,
struct ArrowDecimal*
value);
static inline void ArrowArrayViewGetDecimalUnsafe(struct ArrowArrayView*
array_view,
int64_t i, struct
ArrowDecimal* out);
```
---
src/nanoarrow/array_inline.h | 52 ++++++++++++++
src/nanoarrow/array_test.cc | 154 ++++++++++++++++++++++++++++++++++++++++
src/nanoarrow/nanoarrow.h | 16 +++++
src/nanoarrow/nanoarrow_types.h | 91 ++++++++++++++++++++++++
src/nanoarrow/utils_test.cc | 75 +++++++++++++++++++
5 files changed, 388 insertions(+)
diff --git a/src/nanoarrow/array_inline.h b/src/nanoarrow/array_inline.h
index bcb2fe7..397c7ce 100644
--- a/src/nanoarrow/array_inline.h
+++ b/src/nanoarrow/array_inline.h
@@ -519,6 +519,41 @@ static inline ArrowErrorCode ArrowArrayAppendString(struct
ArrowArray* array,
}
}
+static inline ArrowErrorCode ArrowArrayAppendDecimal(struct ArrowArray* array,
+ struct ArrowDecimal*
value) {
+ struct ArrowArrayPrivateData* private_data =
+ (struct ArrowArrayPrivateData*)array->private_data;
+ struct ArrowBuffer* data_buffer = ArrowArrayBuffer(array, 1);
+
+ switch (private_data->storage_type) {
+ case NANOARROW_TYPE_DECIMAL128:
+ if (value->n_words != 2) {
+ return EINVAL;
+ } else {
+ NANOARROW_RETURN_NOT_OK(
+ ArrowBufferAppend(data_buffer, value->words, 2 *
sizeof(uint64_t)));
+ break;
+ }
+ case NANOARROW_TYPE_DECIMAL256:
+ if (value->n_words != 4) {
+ return EINVAL;
+ } else {
+ NANOARROW_RETURN_NOT_OK(
+ ArrowBufferAppend(data_buffer, value->words, 4 *
sizeof(uint64_t)));
+ break;
+ }
+ default:
+ return EINVAL;
+ }
+
+ if (private_data->bitmap.buffer.data != NULL) {
+ NANOARROW_RETURN_NOT_OK(ArrowBitmapAppend(ArrowArrayValidityBitmap(array),
1, 1));
+ }
+
+ array->length++;
+ return NANOARROW_OK;
+}
+
static inline ArrowErrorCode ArrowArrayFinishElement(struct ArrowArray* array)
{
struct ArrowArrayPrivateData* private_data =
(struct ArrowArrayPrivateData*)array->private_data;
@@ -828,6 +863,23 @@ static inline struct ArrowBufferView
ArrowArrayViewGetBytesUnsafe(
return view;
}
+static inline void ArrowArrayViewGetDecimalUnsafe(struct ArrowArrayView*
array_view,
+ int64_t i, struct
ArrowDecimal* out) {
+ i += array_view->array->offset;
+ const uint8_t* data_view = array_view->buffer_views[1].data.as_uint8;
+ switch (array_view->storage_type) {
+ case NANOARROW_TYPE_DECIMAL128:
+ ArrowDecimalSetBytes(out, data_view + (i * 16));
+ break;
+ case NANOARROW_TYPE_DECIMAL256:
+ ArrowDecimalSetBytes(out, data_view + (i * 32));
+ break;
+ default:
+ memset(out->words, 0, sizeof(out->words));
+ break;
+ }
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/src/nanoarrow/array_test.cc b/src/nanoarrow/array_test.cc
index 493541f..4b27bda 100644
--- a/src/nanoarrow/array_test.cc
+++ b/src/nanoarrow/array_test.cc
@@ -20,11 +20,13 @@
#include <arrow/array.h>
#include <arrow/array/builder_binary.h>
+#include <arrow/array/builder_decimal.h>
#include <arrow/array/builder_nested.h>
#include <arrow/array/builder_primitive.h>
#include <arrow/array/builder_union.h>
#include <arrow/c/bridge.h>
#include <arrow/compare.h>
+#include <arrow/util/decimal.h>
#include "nanoarrow/nanoarrow.h"
@@ -872,6 +874,86 @@ TEST(ArrayTest, ArrayTestAppendToFixedSizeBinaryArray) {
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
+TEST(ArrayTest, ArrayTestAppendToDecimal128Array) {
+ struct ArrowArray array;
+ struct ArrowDecimal decimal;
+
+ ArrowDecimalInit(&decimal, 128, 10, 3);
+ ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DECIMAL128),
NANOARROW_OK);
+ EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
+
+ EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
+
+ ArrowDecimalSetInt(&decimal, -67890);
+ EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
+
+ EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
+ EXPECT_EQ(array.length, 4);
+ EXPECT_EQ(array.null_count, 2);
+ auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
+ auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
+ EXPECT_EQ(validity_buffer[0], 0b00001001);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(memcmp(data_buffer, decimal.words, 16), 0);
+ ArrowDecimalSetInt(&decimal, -67890);
+ EXPECT_EQ(memcmp(data_buffer + 3 * 16, decimal.words, 16), 0);
+
+ auto arrow_array = ImportArray(&array, decimal128(10, 3));
+ ARROW_EXPECT_OK(arrow_array);
+
+ auto builder = Decimal128Builder(decimal128(10, 3));
+ ARROW_EXPECT_OK(builder.Append(*Decimal128::FromString("12.345")));
+ ARROW_EXPECT_OK(builder.AppendNulls(2));
+ ARROW_EXPECT_OK(builder.Append(*Decimal128::FromString("-67.890")));
+ auto expected_array = builder.Finish();
+
+ EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
+}
+
+TEST(ArrayTest, ArrayTestAppendToDecimal256Array) {
+ struct ArrowArray array;
+ struct ArrowDecimal decimal;
+
+ ArrowDecimalInit(&decimal, 256, 10, 3);
+ ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DECIMAL256),
NANOARROW_OK);
+ EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
+
+ EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
+
+ ArrowDecimalSetInt(&decimal, -67890);
+ EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
+
+ EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
+ EXPECT_EQ(array.length, 4);
+ EXPECT_EQ(array.null_count, 2);
+ auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
+ auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
+ EXPECT_EQ(validity_buffer[0], 0b00001001);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(memcmp(data_buffer, decimal.words, 32), 0);
+ ArrowDecimalSetInt(&decimal, -67890);
+ EXPECT_EQ(memcmp(data_buffer + 3 * 32, decimal.words, 32), 0);
+
+ auto arrow_array = ImportArray(&array, decimal256(10, 3));
+ ARROW_EXPECT_OK(arrow_array);
+
+ auto builder = Decimal256Builder(decimal256(10, 3));
+ ARROW_EXPECT_OK(builder.Append(*Decimal256::FromString("12.345")));
+ ARROW_EXPECT_OK(builder.AppendNulls(2));
+ ARROW_EXPECT_OK(builder.Append(*Decimal256::FromString("-67.890")));
+ auto expected_array = builder.Finish();
+
+ EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
+}
+
TEST(ArrayTest, ArrayTestAppendToListArray) {
struct ArrowArray array;
struct ArrowSchema schema;
@@ -2107,3 +2189,75 @@ TEST(ArrayViewTest, ArrayViewTestGetString) {
auto fixed_size_builder = FixedSizeBinaryBuilder(fixed_size_binary(4));
TestGetFromBinary<FixedSizeBinaryBuilder>(fixed_size_builder);
}
+
+TEST(ArrayViewTest, ArrayViewTestGetDecimal128) {
+ struct ArrowArray array;
+ struct ArrowSchema schema;
+ struct ArrowArrayView array_view;
+ struct ArrowError error;
+
+ auto type = decimal128(10, 3);
+
+ // Array with nulls
+ auto builder = Decimal128Builder(type);
+ ARROW_EXPECT_OK(builder.Append(*Decimal128::FromReal(1.234, 10, 3)));
+ ARROW_EXPECT_OK(builder.AppendNulls(2));
+ ARROW_EXPECT_OK(builder.Append(*Decimal128::FromReal(-5.678, 10, 3)));
+ auto maybe_arrow_array = builder.Finish();
+ ARROW_EXPECT_OK(maybe_arrow_array);
+ auto arrow_array = maybe_arrow_array.ValueUnsafe();
+
+ ARROW_EXPECT_OK(ExportArray(*arrow_array, &array, &schema));
+ ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error),
NANOARROW_OK);
+ ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
+ EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
+
+ ArrowDecimal decimal;
+ ArrowDecimalInit(&decimal, 128, 10, 3);
+
+ ArrowArrayViewGetDecimalUnsafe(&array_view, 0, &decimal);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), 1234);
+
+ ArrowArrayViewGetDecimalUnsafe(&array_view, 3, &decimal);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), -5678);
+
+ ArrowArrayViewReset(&array_view);
+ schema.release(&schema);
+ array.release(&array);
+}
+
+TEST(ArrayViewTest, ArrayViewTestGetDecimal256) {
+ struct ArrowArray array;
+ struct ArrowSchema schema;
+ struct ArrowArrayView array_view;
+ struct ArrowError error;
+
+ auto type = decimal256(10, 3);
+
+ // Array with nulls
+ auto builder = Decimal256Builder(type);
+ ARROW_EXPECT_OK(builder.Append(*Decimal256::FromReal(1.234, 10, 3)));
+ ARROW_EXPECT_OK(builder.AppendNulls(2));
+ ARROW_EXPECT_OK(builder.Append(*Decimal256::FromReal(-5.678, 10, 3)));
+ auto maybe_arrow_array = builder.Finish();
+ ARROW_EXPECT_OK(maybe_arrow_array);
+ auto arrow_array = maybe_arrow_array.ValueUnsafe();
+
+ ARROW_EXPECT_OK(ExportArray(*arrow_array, &array, &schema));
+ ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error),
NANOARROW_OK);
+ ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
+ EXPECT_EQ(ArrowArrayViewValidateFull(&array_view, &error), NANOARROW_OK);
+
+ ArrowDecimal decimal;
+ ArrowDecimalInit(&decimal, 256, 10, 3);
+
+ ArrowArrayViewGetDecimalUnsafe(&array_view, 0, &decimal);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), 1234);
+
+ ArrowArrayViewGetDecimalUnsafe(&array_view, 3, &decimal);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), -5678);
+
+ ArrowArrayViewReset(&array_view);
+ schema.release(&schema);
+ array.release(&array);
+}
diff --git a/src/nanoarrow/nanoarrow.h b/src/nanoarrow/nanoarrow.h
index 9b67c4f..09ee85d 100644
--- a/src/nanoarrow/nanoarrow.h
+++ b/src/nanoarrow/nanoarrow.h
@@ -824,12 +824,20 @@ static inline ArrowErrorCode ArrowArrayAppendBytes(struct
ArrowArray* array,
struct ArrowBufferView
value);
/// \brief Append a string value to an array
+///
/// Returns NANOARROW_OK if value can be exactly represented by
/// the underlying storage type or EINVAL otherwise (e.g.,
/// the underlying array is not a string or large string array).
static inline ArrowErrorCode ArrowArrayAppendString(struct ArrowArray* array,
struct ArrowStringView
value);
+/// \brief Append a decimal value to an array
+///
+/// Returns NANOARROW_OK if array is a decimal array with the appropriate
+/// bitwidth or EINVAL otherwise.
+static inline ArrowErrorCode ArrowArrayAppendDecimal(struct ArrowArray* array,
+ struct ArrowDecimal*
value);
+
/// \brief Finish a nested array element
///
/// Appends a non-null element to the array based on the first child's current
@@ -966,6 +974,14 @@ static inline struct ArrowStringView
ArrowArrayViewGetStringUnsafe(
static inline struct ArrowBufferView ArrowArrayViewGetBytesUnsafe(
struct ArrowArrayView* array_view, int64_t i);
+/// \brief Get an element in an ArrowArrayView as an ArrowDecimal
+///
+/// This function does not check for null values. The out parameter must
+/// be initialized with ArrowDecimalInit() with the proper parameters for this
+/// type before calling this for the first time.
+static inline void ArrowArrayViewGetDecimalUnsafe(struct ArrowArrayView*
array_view,
+ int64_t i, struct
ArrowDecimal* out);
+
/// @}
/// \defgroup nanoarrow-basic-array-stream Basic ArrowArrayStream
implementation
diff --git a/src/nanoarrow/nanoarrow_types.h b/src/nanoarrow/nanoarrow_types.h
index c8eede8..ee380de 100644
--- a/src/nanoarrow/nanoarrow_types.h
+++ b/src/nanoarrow/nanoarrow_types.h
@@ -172,6 +172,13 @@ typedef int ArrowErrorCode;
#define NANOARROW_RETURN_NOT_OK(EXPR) \
_NANOARROW_RETURN_NOT_OK_IMPL(_NANOARROW_MAKE_NAME(errno_status_,
__COUNTER__), EXPR)
+static char _ArrowIsLittleEndian(void) {
+ uint32_t check = 1;
+ char first_byte;
+ memcpy(&first_byte, &check, sizeof(char));
+ return first_byte;
+}
+
/// \brief Arrow type enumerator
/// \ingroup nanoarrow-utils
///
@@ -554,6 +561,90 @@ struct ArrowArrayPrivateData {
int8_t union_type_id_is_child_index;
};
+/// \brief A representation of a fixed-precision decimal number
+/// \ingroup nanoarrow-utils
+///
+/// This structure should be initialized with ArrowDecimalInit() once and
+/// values set using ArrowDecimalSetInt(), ArrowDecimalSetBytes128(),
+/// or ArrowDecimalSetBytes256().
+struct ArrowDecimal {
+ /// \brief An array of 64-bit integers of n_words length defined in
native-endian order
+ uint64_t words[4];
+
+ /// \brief The number of significant digits this decimal number can represent
+ int32_t precision;
+
+ /// \brief The number of digits after the decimal point. This can be
negative.
+ int32_t scale;
+
+ /// \brief The number of words in the words array
+ int n_words;
+
+ /// \brief Cached value used by the implementation
+ int high_word_index;
+
+ /// \brief Cached value used by the implementation
+ int low_word_index;
+};
+
+/// \brief Initialize a decimal with a given set of type parameters
+/// \ingroup nanoarrow-utils
+static inline void ArrowDecimalInit(struct ArrowDecimal* decimal, int32_t
bitwidth,
+ int32_t precision, int32_t scale) {
+ memset(decimal->words, 0, sizeof(decimal->words));
+ decimal->precision = precision;
+ decimal->scale = scale;
+ decimal->n_words = bitwidth / 8 / sizeof(uint64_t);
+
+ if (_ArrowIsLittleEndian()) {
+ decimal->low_word_index = 0;
+ decimal->high_word_index = decimal->n_words - 1;
+ } else {
+ decimal->low_word_index = decimal->n_words - 1;
+ decimal->high_word_index = 0;
+ }
+}
+
+/// \brief Get a signed integer value of a sufficiently small ArrowDecimal
+///
+/// This does not check if the decimal's precision sufficiently small to fit
+/// within the signed 64-bit integer range (A precision less than or equal
+/// to 18 is sufficiently small).
+static inline int64_t ArrowDecimalGetIntUnsafe(struct ArrowDecimal* decimal) {
+ return (int64_t)decimal->words[decimal->low_word_index];
+}
+
+/// \brief Copy the bytes of this decimal into a sufficiently large buffer
+/// \ingroup nanoarrow-utils
+static inline void ArrowDecimalGetBytes(struct ArrowDecimal* decimal, uint8_t*
out) {
+ memcpy(out, decimal->words, decimal->n_words * sizeof(uint64_t));
+}
+
+/// \brief Returns 1 if the value represented by decimal is >= 0 or -1
otherwise
+/// \ingroup nanoarrow-utils
+static inline int64_t ArrowDecimalSign(struct ArrowDecimal* decimal) {
+ return 1 | ((int64_t)(decimal->words[decimal->high_word_index]) >> 63);
+}
+
+/// \brief Sets the integer value of this decimal
+/// \ingroup nanoarrow-utils
+static inline void ArrowDecimalSetInt(struct ArrowDecimal* decimal, int64_t
value) {
+ if (value < 0) {
+ memset(decimal->words, 0xff, decimal->n_words * sizeof(uint64_t));
+ } else {
+ memset(decimal->words, 0, decimal->n_words * sizeof(uint64_t));
+ }
+
+ decimal->words[decimal->low_word_index] = value;
+}
+
+/// \brief Copy bytes from a buffer into this decimal
+/// \ingroup nanoarrow-utils
+static inline void ArrowDecimalSetBytes(struct ArrowDecimal* decimal,
+ const uint8_t* value) {
+ memcpy(decimal->words, value, decimal->n_words * sizeof(uint64_t));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/src/nanoarrow/utils_test.cc b/src/nanoarrow/utils_test.cc
index 5506a6e..74bb377 100644
--- a/src/nanoarrow/utils_test.cc
+++ b/src/nanoarrow/utils_test.cc
@@ -19,6 +19,7 @@
#include <string>
#include <arrow/memory_pool.h>
+#include <arrow/util/decimal.h>
#include <gtest/gtest.h>
#include "nanoarrow/nanoarrow.h"
@@ -150,3 +151,77 @@ TEST(AllocatorTest, AllocatorTestMemoryPool) {
std::numeric_limits<int64_t>::max());
EXPECT_EQ(buffer, nullptr);
}
+
+TEST(DecimalTest, Decimal128Test) {
+ struct ArrowDecimal decimal;
+ ArrowDecimalInit(&decimal, 128, 10, 3);
+
+ EXPECT_EQ(decimal.n_words, 2);
+ EXPECT_EQ(decimal.precision, 10);
+ EXPECT_EQ(decimal.scale, 3);
+
+ if (_ArrowIsLittleEndian()) {
+ EXPECT_EQ(decimal.high_word_index - decimal.low_word_index + 1,
decimal.n_words);
+ } else {
+ EXPECT_EQ(decimal.low_word_index - decimal.high_word_index + 1,
decimal.n_words);
+ }
+
+ auto dec_pos = *Decimal128::FromString("12.345");
+ uint8_t bytes_pos[16];
+ dec_pos.ToBytes(bytes_pos);
+
+ auto dec_neg = *Decimal128::FromString("-34.567");
+ uint8_t bytes_neg[16];
+ dec_neg.ToBytes(bytes_neg);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), 12345);
+ EXPECT_EQ(ArrowDecimalSign(&decimal), 1);
+ EXPECT_EQ(memcmp(decimal.words, bytes_pos, sizeof(bytes_pos)), 0);
+ ArrowDecimalSetBytes(&decimal, bytes_pos);
+ EXPECT_EQ(memcmp(decimal.words, bytes_pos, sizeof(bytes_pos)), 0);
+
+ ArrowDecimalSetInt(&decimal, -34567);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), -34567);
+ EXPECT_EQ(ArrowDecimalSign(&decimal), -1);
+ EXPECT_EQ(memcmp(decimal.words, bytes_neg, sizeof(bytes_neg)), 0);
+ ArrowDecimalSetBytes(&decimal, bytes_neg);
+ EXPECT_EQ(memcmp(decimal.words, bytes_neg, sizeof(bytes_neg)), 0);
+}
+
+TEST(DecimalTest, Decimal256Test) {
+ struct ArrowDecimal decimal;
+ ArrowDecimalInit(&decimal, 256, 10, 3);
+
+ EXPECT_EQ(decimal.n_words, 4);
+ EXPECT_EQ(decimal.precision, 10);
+ EXPECT_EQ(decimal.scale, 3);
+
+ if (_ArrowIsLittleEndian()) {
+ EXPECT_EQ(decimal.high_word_index - decimal.low_word_index + 1,
decimal.n_words);
+ } else {
+ EXPECT_EQ(decimal.low_word_index - decimal.high_word_index + 1,
decimal.n_words);
+ }
+
+ auto dec_pos = *Decimal256::FromString("12.345");
+ uint8_t bytes_pos[32];
+ dec_pos.ToBytes(bytes_pos);
+
+ ArrowDecimalSetInt(&decimal, 12345);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), 12345);
+ EXPECT_EQ(ArrowDecimalSign(&decimal), 1);
+ EXPECT_EQ(memcmp(decimal.words, bytes_pos, sizeof(bytes_pos)), 0);
+ ArrowDecimalSetBytes(&decimal, bytes_pos);
+ EXPECT_EQ(memcmp(decimal.words, bytes_pos, sizeof(bytes_pos)), 0);
+
+ auto dec_neg = *Decimal256::FromString("-34.567");
+ uint8_t bytes_neg[32];
+ dec_neg.ToBytes(bytes_neg);
+
+ ArrowDecimalSetInt(&decimal, -34567);
+ EXPECT_EQ(ArrowDecimalGetIntUnsafe(&decimal), -34567);
+ EXPECT_EQ(ArrowDecimalSign(&decimal), -1);
+ EXPECT_EQ(memcmp(decimal.words, bytes_neg, sizeof(bytes_neg)), 0);
+ ArrowDecimalSetBytes(&decimal, bytes_neg);
+ EXPECT_EQ(memcmp(decimal.words, bytes_neg, sizeof(bytes_neg)), 0);
+}