21
21
#include <R.h>
22
22
#include <Rinternals.h>
23
23
24
+ #include "buffer.h"
24
25
#include "materialize_common.h"
25
26
#include "nanoarrow.h"
26
27
27
28
// bit64::as.integer64(2^53)
28
29
#define MAX_DBL_AS_INTEGER 9007199254740992
29
30
31
+ static inline int nanoarrow_decimal_to_chr (struct ArrowDecimal * item ,
32
+ struct ArrowBuffer * buffer , int scale );
33
+
30
34
static inline int nanoarrow_materialize_dbl (struct RConverter * converter ) {
31
35
if (converter -> src .array_view -> array -> dictionary != NULL ) {
32
36
return ENOTSUP ;
@@ -109,6 +113,43 @@ static inline int nanoarrow_materialize_dbl(struct RConverter* converter) {
109
113
}
110
114
break ;
111
115
116
+ case NANOARROW_TYPE_DECIMAL32 :
117
+ case NANOARROW_TYPE_DECIMAL64 :
118
+ case NANOARROW_TYPE_DECIMAL128 :
119
+ case NANOARROW_TYPE_DECIMAL256 : {
120
+ struct ArrowDecimal item ;
121
+ ArrowDecimalInit (& item , converter -> schema_view .decimal_bitwidth ,
122
+ converter -> schema_view .decimal_precision ,
123
+ converter -> schema_view .decimal_scale );
124
+
125
+ // Buffer to manage the building of the digits output
126
+ SEXP buffer_xptr = PROTECT (buffer_owning_xptr ());
127
+ struct ArrowBuffer * digits = (struct ArrowBuffer * )R_ExternalPtrAddr (buffer_xptr );
128
+
129
+ // A length one character() we'll use as input to Rf_asReal()
130
+ SEXP decimal_as_chr = PROTECT (Rf_allocVector (STRSXP , 1 ));
131
+
132
+ for (R_xlen_t i = 0 ; i < dst -> length ; i ++ ) {
133
+ if (is_valid != NULL && !ArrowBitGet (is_valid , raw_src_offset + i )) {
134
+ result [dst -> offset + i ] = NA_REAL ;
135
+ continue ;
136
+ }
137
+
138
+ ArrowArrayViewGetDecimalUnsafe (src -> array_view , src -> offset + i , & item );
139
+ int status = nanoarrow_decimal_to_chr (& item , digits , item .scale );
140
+ if (status != NANOARROW_OK ) {
141
+ UNPROTECT (2 );
142
+ return status ;
143
+ }
144
+
145
+ SET_STRING_ELT (decimal_as_chr , i ,
146
+ Rf_mkCharLen ((char * )digits -> data , (int )digits -> size_bytes ));
147
+ result [dst -> offset + i ] = Rf_asReal (decimal_as_chr );
148
+ }
149
+ UNPROTECT (2 );
150
+ return NANOARROW_OK ;
151
+ }
152
+
112
153
default :
113
154
return EINVAL ;
114
155
}
@@ -121,4 +162,47 @@ static inline int nanoarrow_materialize_dbl(struct RConverter* converter) {
121
162
return NANOARROW_OK ;
122
163
}
123
164
165
+ static inline int nanoarrow_decimal_to_chr (struct ArrowDecimal * item ,
166
+ struct ArrowBuffer * buffer , int scale ) {
167
+ buffer -> size_bytes = 0 ;
168
+ NANOARROW_RETURN_NOT_OK (ArrowDecimalAppendDigitsToBuffer (item , buffer ));
169
+
170
+ if (scale <= 0 ) {
171
+ // e.g., digits are -12345 and scale is -2 -> -1234500
172
+ // Just add zeros to the end
173
+ for (int i = scale ; i <= 0 ; i ++ ) {
174
+ NANOARROW_RETURN_NOT_OK (ArrowBufferAppendInt8 (buffer , '0' ));
175
+ }
176
+ return NANOARROW_OK ;
177
+ }
178
+
179
+ int is_negative = buffer -> data [0 ] == '-' ;
180
+ int64_t num_digits = buffer -> size_bytes - is_negative ;
181
+ if (num_digits <= scale ) {
182
+ // e.g., digits are -12345 and scale is 6 -> -0.012345
183
+ // Insert "0.<some zeros>" between the (maybe) negative sign and the digits
184
+ int num_zeros_after_decimal = scale - num_digits ;
185
+ NANOARROW_RETURN_NOT_OK (
186
+ ArrowBufferResize (buffer , buffer -> size_bytes + num_zeros_after_decimal + 2 , 0 ));
187
+
188
+ uint8_t * digits_start = buffer -> data + is_negative ;
189
+ memmove (digits_start + num_zeros_after_decimal + 2 , digits_start , num_digits );
190
+ * digits_start ++ = '0' ;
191
+ * digits_start ++ = '.' ;
192
+ for (int i = 0 ; i < num_zeros_after_decimal ; i ++ ) {
193
+ * digits_start ++ = '0' ;
194
+ }
195
+
196
+ } else {
197
+ // e.g., digits are -12345 and scale is 4 -> -1.2345
198
+ // Insert a decimal point before scale digits of output
199
+ NANOARROW_RETURN_NOT_OK (ArrowBufferResize (buffer , buffer -> size_bytes + 1 , 0 ));
200
+ uint8_t * decimal_point_to_be = buffer -> data + buffer -> size_bytes - 1 - scale ;
201
+ memmove (decimal_point_to_be + 1 , decimal_point_to_be , scale );
202
+ * decimal_point_to_be = '.' ;
203
+ }
204
+
205
+ return NANOARROW_OK ;
206
+ }
207
+
124
208
#endif
0 commit comments