nanoarrow 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7006022b54eed1e4dbe453d1cb591afe02983bd1d48af8a1adde8100156e932
4
- data.tar.gz: 1358afb3611b1b4a046e1f275c506b32c824b87e9af05f01541bad58c8e7f9e1
3
+ metadata.gz: decb8918e601df4caf34ed3f7b3e0156e8cc786b8c71d9319eeeac232cfbd1bb
4
+ data.tar.gz: cebef59fcd99d497795f96286cc0442f3d2469f87b6f81245ccb30dd33231dfe
5
5
  SHA512:
6
- metadata.gz: cf2d3c844f5fcdf77e9ec9e3bd402ae466e990a9ae4c9cc536cc7e1a3844118b3a8d30128fc0384090d8c6acd9a1b8e9740d90614005c652b00cc473f8735d30
7
- data.tar.gz: 5be7d313f2ee69ee4fe2623b144c3eec53e4ef131be7de0075771891248a67ffdd6201272f54bbef7582381c20f758b88103ce98742f722a91b5e27dab4eac2c
6
+ metadata.gz: a55d007c99986854f1b91b30a8578b8873d192a3ff9b8dbeec02ac4cf0eb22ec1a5db8dc2510c8b6d0557fbaa0f9f5e1c595a7250b08079633ab1f9e381e6ea7
7
+ data.tar.gz: 526031a467ecb8266d641bd0947a3c67f252e5b77f52f3b2fb7dedcdf28f4a1f3a767505ada6d5f0ddf0e1e705e1d11cb9a8c196b93452bae5ad60c4dcf37076
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.1.4 (2026-09-21)
2
+
3
+ - Updated nanoarrow to 0.9.0
4
+
1
5
  ## 0.1.3 (2026-08-05)
2
6
 
3
7
  - Fixed issue with GC compaction
@@ -19,9 +19,9 @@
19
19
  #define NANOARROW_CONFIG_H_INCLUDED
20
20
 
21
21
  #define NANOARROW_VERSION_MAJOR 0
22
- #define NANOARROW_VERSION_MINOR 8
22
+ #define NANOARROW_VERSION_MINOR 9
23
23
  #define NANOARROW_VERSION_PATCH 0
24
- #define NANOARROW_VERSION "0.8.0"
24
+ #define NANOARROW_VERSION "0.9.0"
25
25
 
26
26
  #define NANOARROW_VERSION_INT \
27
27
  (NANOARROW_VERSION_MAJOR * 10000 + NANOARROW_VERSION_MINOR * 100 + \
@@ -181,6 +181,13 @@ struct ArrowArrayStream {
181
181
  if (NAME) return NAME; \
182
182
  } while (0)
183
183
 
184
+ // __COUNTER__ is not guaranteed to be available and some compiler warnings may occur
185
+ // if we use it (-Wc2y-extensions). We don't strictly need it because of the
186
+ // do { ... } while(0) scoping and because we never need the return value to live
187
+ // outside the temporary scope. Here we define a suffix that is unlikely to collide
188
+ // with anything in EXPR.
189
+ #define _NANOARROW_UNIQUE_SUFFIX _nanoarrow_unique_suffix
190
+
184
191
  #define _NANOARROW_CHECK_RANGE(x_, min_, max_) \
185
192
  NANOARROW_RETURN_NOT_OK((x_ >= min_ && x_ <= max_) ? NANOARROW_OK : EINVAL)
186
193
 
@@ -305,7 +312,8 @@ static inline void ArrowErrorSetString(struct ArrowError* error, const char* src
305
312
  /// \brief Check the result of an expression and return it if not NANOARROW_OK
306
313
  /// \ingroup nanoarrow-errors
307
314
  #define NANOARROW_RETURN_NOT_OK(EXPR) \
308
- _NANOARROW_RETURN_NOT_OK_IMPL(_NANOARROW_MAKE_NAME(errno_status_, __COUNTER__), EXPR)
315
+ _NANOARROW_RETURN_NOT_OK_IMPL( \
316
+ _NANOARROW_MAKE_NAME(errno_status_, _NANOARROW_UNIQUE_SUFFIX), EXPR)
309
317
 
310
318
  /// \brief Check the result of an expression and return it if not NANOARROW_OK,
311
319
  /// adding an auto-generated message to an ArrowError.
@@ -314,9 +322,10 @@ static inline void ArrowErrorSetString(struct ArrowError* error, const char* src
314
322
  /// This macro is used to ensure that functions that accept an ArrowError
315
323
  /// as input always set its message when returning an error code (e.g., when calling
316
324
  /// a nanoarrow function that does *not* accept ArrowError).
317
- #define NANOARROW_RETURN_NOT_OK_WITH_ERROR(EXPR, ERROR_EXPR) \
318
- _NANOARROW_RETURN_NOT_OK_WITH_ERROR_IMPL( \
319
- _NANOARROW_MAKE_NAME(errno_status_, __COUNTER__), EXPR, ERROR_EXPR, #EXPR)
325
+ #define NANOARROW_RETURN_NOT_OK_WITH_ERROR(EXPR, ERROR_EXPR) \
326
+ _NANOARROW_RETURN_NOT_OK_WITH_ERROR_IMPL( \
327
+ _NANOARROW_MAKE_NAME(errno_status_, _NANOARROW_UNIQUE_SUFFIX), EXPR, ERROR_EXPR, \
328
+ #EXPR)
320
329
 
321
330
  #if defined(NANOARROW_DEBUG) && !defined(NANOARROW_PRINT_AND_DIE)
322
331
  #define NANOARROW_PRINT_AND_DIE(VALUE, EXPR_STR) \
@@ -343,7 +352,8 @@ static inline void ArrowErrorSetString(struct ArrowError* error, const char* src
343
352
  /// be defining the NANOARROW_PRINT_AND_DIE macro before including nanoarrow.h
344
353
  /// This macro is provided as a convenience for users and is not used internally.
345
354
  #define NANOARROW_ASSERT_OK(EXPR) \
346
- _NANOARROW_ASSERT_OK_IMPL(_NANOARROW_MAKE_NAME(errno_status_, __COUNTER__), EXPR, #EXPR)
355
+ _NANOARROW_ASSERT_OK_IMPL( \
356
+ _NANOARROW_MAKE_NAME(errno_status_, _NANOARROW_UNIQUE_SUFFIX), EXPR, #EXPR)
347
357
 
348
358
  #define _NANOARROW_DCHECK_IMPL(EXPR, EXPR_STR) \
349
359
  do { \
@@ -502,7 +512,7 @@ enum ArrowType {
502
512
  /// \brief Get a string value of an enum ArrowType value
503
513
  /// \ingroup nanoarrow-utils
504
514
  ///
505
- /// Returns NULL for invalid values for type
515
+ /// Returns "<unknown type identifier>" for invalid values for type
506
516
  static inline const char* ArrowTypeString(enum ArrowType type);
507
517
 
508
518
  static inline const char* ArrowTypeString(enum ArrowType type) {
@@ -598,7 +608,7 @@ static inline const char* ArrowTypeString(enum ArrowType type) {
598
608
  case NANOARROW_TYPE_LARGE_LIST_VIEW:
599
609
  return "large_list_view";
600
610
  default:
601
- return NULL;
611
+ return "<unknown type identifier>";
602
612
  }
603
613
  }
604
614
 
@@ -1130,6 +1140,17 @@ static inline void ArrowDecimalSetBytes(struct ArrowDecimal* decimal,
1130
1140
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowBufferAllocatorDefault)
1131
1141
  #define ArrowBufferDeallocator \
1132
1142
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowBufferDeallocator)
1143
+ #define ArrowSharedBufferInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedBufferInit)
1144
+ #define ArrowSharedBufferIsThreadSafe \
1145
+ NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedBufferIsThreadSafe)
1146
+ #define ArrowSharedBufferClone \
1147
+ NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedBufferClone)
1148
+ #define ArrowSharedArrayInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedArrayInit)
1149
+ #define ArrowSharedArrayRelease \
1150
+ NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedArrayRelease)
1151
+ #define ArrowSharedArrayBuffer \
1152
+ NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSharedArrayBuffer)
1153
+ #define ArrowIsSharedBuffer NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowIsSharedBuffer)
1133
1154
  #define ArrowErrorSet NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowErrorSet)
1134
1155
  #define ArrowLayoutInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowLayoutInit)
1135
1156
  #define ArrowDecimalSetDigits NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowDecimalSetDigits)
@@ -1179,6 +1200,7 @@ static inline void ArrowDecimalSetBytes(struct ArrowDecimal* decimal,
1179
1200
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowMetadataBuilderRemove)
1180
1201
  #define ArrowSchemaViewInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaViewInit)
1181
1202
  #define ArrowSchemaToString NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaToString)
1203
+ #define ArrowArrayIsInternal NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayIsInternal)
1182
1204
  #define ArrowArrayInitFromType \
1183
1205
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayInitFromType)
1184
1206
  #define ArrowArrayInitFromSchema \
@@ -1199,6 +1221,8 @@ static inline void ArrowDecimalSetBytes(struct ArrowDecimal* decimal,
1199
1221
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayFinishBuilding)
1200
1222
  #define ArrowArrayFinishBuildingDefault \
1201
1223
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayFinishBuildingDefault)
1224
+ #define ArrowArrayMoveShared NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayMoveShared)
1225
+ #define ArrowArrayCloneShared NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayCloneShared)
1202
1226
  #define ArrowArrayViewInitFromType \
1203
1227
  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayViewInitFromType)
1204
1228
  #define ArrowArrayViewInitFromSchema \
@@ -1288,6 +1312,85 @@ NANOARROW_DLL struct ArrowBufferAllocator ArrowBufferDeallocator(
1288
1312
 
1289
1313
  /// @}
1290
1314
 
1315
+ /// \defgroup nanoarrow-shared-buffer Shared buffers and arrays
1316
+ ///
1317
+ /// The nanoarrow library implements two kinds of shared buffers: those backed by
1318
+ /// a reference-counted ArrowBuffer and those backed by a reference-counted ArrowArray.
1319
+ /// These are useful for building ArrowArrays using buffers without copying the bytes
1320
+ /// of the source. For example the IPC implementation uses shared buffers derived from an
1321
+ /// ArrowBuffer to avoid copying buffers from an IPC message, and the Shared buffers
1322
+ /// derived from arrays are used to make a safe shallow clone of an array.
1323
+ ///
1324
+ /// Reference counts are implemented using C11 atomics and not necessarily thread safe
1325
+ /// on all platforms (notably, MSVC requires `/experimental:c11atomics`). Use
1326
+ /// ArrowSharedBufferIsThreadSafe() to check for thread safety if this is needed.
1327
+ ///
1328
+ /// @{
1329
+
1330
+ /// \brief Initialize a shared buffer from an ArrowBuffer
1331
+ ///
1332
+ /// If NANOARROW_OK is returned, shared is a reference-counted buffer that
1333
+ /// took ownership of src. The caller should release the shared buffer
1334
+ /// using ArrowBufferReset() when finished. The underlying data will persist
1335
+ /// until all clones have also been released.
1336
+ NANOARROW_DLL ArrowErrorCode ArrowSharedBufferInit(struct ArrowBuffer* shared,
1337
+ struct ArrowBuffer* src);
1338
+
1339
+ /// \brief Check for shared buffer thread safety
1340
+ ///
1341
+ /// Thread-safe shared buffers require C11 and the stdatomic.h header.
1342
+ /// If either are unavailable, shared buffers are still possible but
1343
+ /// the resulting arrays must not be passed to other threads to be released.
1344
+ NANOARROW_DLL int ArrowSharedBufferIsThreadSafe(void);
1345
+
1346
+ /// \brief Check if a buffer is a shared buffer
1347
+ ///
1348
+ /// Returns non-zero if buffer was created by ArrowSharedBufferInit() or
1349
+ /// obtained from ArrowSharedArrayBuffer().
1350
+ NANOARROW_DLL int ArrowIsSharedBuffer(struct ArrowBuffer* buffer);
1351
+
1352
+ /// \brief Clone a shared buffer, incrementing its reference count
1353
+ ///
1354
+ /// This creates a new ArrowBuffer that shares the same underlying data with the
1355
+ /// original shared buffer. The reference count is incremented. Returns EINVAL
1356
+ /// if shared is not a shared buffer (i.e. ArrowIsSharedBuffer() returns false).
1357
+ NANOARROW_DLL ArrowErrorCode ArrowSharedBufferClone(struct ArrowBuffer* shared,
1358
+ struct ArrowBuffer* shared_out);
1359
+
1360
+ /// \brief An opaque handle to a shared, reference-counted ArrowArray
1361
+ struct ArrowSharedArray {
1362
+ void* private_data;
1363
+ };
1364
+
1365
+ /// \brief Initialize a shared array from an ArrowArray
1366
+ ///
1367
+ /// Takes ownership of src (sets src->release to NULL). The shared array
1368
+ /// should be released with ArrowSharedArrayRelease() when all buffers have
1369
+ /// been extracted from the source. The original array will be released
1370
+ /// when all borrowed buffers have been released.
1371
+ NANOARROW_DLL ArrowErrorCode ArrowSharedArrayInit(struct ArrowSharedArray* shared,
1372
+ struct ArrowArray* src);
1373
+
1374
+ /// \brief Release the caller's reference to a shared array
1375
+ ///
1376
+ /// Decrements the reference count. When no more references remain
1377
+ /// (including any buffers obtained via ArrowSharedArrayBuffer()),
1378
+ /// the underlying ArrowArray is released.
1379
+ NANOARROW_DLL void ArrowSharedArrayRelease(struct ArrowSharedArray* shared);
1380
+
1381
+ /// \brief Obtain a buffer from a shared array
1382
+ ///
1383
+ /// Returns an ArrowBuffer that views buffer i of the underlying ArrowArray.
1384
+ /// If the source array was built with nanoarrow (i.e. ArrowArrayIsInternal()
1385
+ /// returns true), buffer sizes are known and propagated to the output.
1386
+ /// Otherwise the output buffer's size_bytes will be 0. The shared array's
1387
+ /// reference count is incremented. The returned buffer is compatible with
1388
+ /// ArrowSharedBufferClone().
1389
+ NANOARROW_DLL ArrowErrorCode ArrowSharedArrayBuffer(struct ArrowSharedArray* shared,
1390
+ int64_t i, struct ArrowBuffer* out);
1391
+
1392
+ /// @}
1393
+
1291
1394
  /// \brief Move the contents of an src ArrowSchema into dst and set src->release to NULL
1292
1395
  /// \ingroup nanoarrow-arrow-cdata
1293
1396
  static inline void ArrowSchemaMove(struct ArrowSchema* src, struct ArrowSchema* dst);
@@ -2123,6 +2226,12 @@ static inline ArrowErrorCode ArrowArrayShrinkToFit(struct ArrowArray* array);
2123
2226
  NANOARROW_DLL ArrowErrorCode ArrowArrayFinishBuildingDefault(struct ArrowArray* array,
2124
2227
  struct ArrowError* error);
2125
2228
 
2229
+ /// \brief Check if an ArrowArray was allocated by nanoarrow
2230
+ ///
2231
+ /// Returns non-zero if array was allocated using ArrowArrayInitFromType(),
2232
+ /// ArrowArrayInitFromSchema(), or ArrowArrayInitFromArrayView().
2233
+ NANOARROW_DLL int ArrowArrayIsInternal(struct ArrowArray* array);
2234
+
2126
2235
  /// \brief Finish building an ArrowArray with explicit validation
2127
2236
  ///
2128
2237
  /// Finish building with an explicit validation level. This could perform less validation
@@ -2134,6 +2243,28 @@ NANOARROW_DLL ArrowErrorCode ArrowArrayFinishBuilding(
2134
2243
  struct ArrowArray* array, enum ArrowValidationLevel validation_level,
2135
2244
  struct ArrowError* error);
2136
2245
 
2246
+ /// \brief Create a shared copy of an ArrowArray
2247
+ ///
2248
+ /// Recursively converts array into a version where all buffers are
2249
+ /// reference-counted. On success, shared is a new ArrowArray whose buffers
2250
+ /// are backed by ArrowSharedArray references, and array is consumed
2251
+ /// (release set to NULL). The resulting shared array can be safely moved
2252
+ /// or have its buffers cloned via ArrowSharedBufferClone(). On error,
2253
+ /// (e.g., failure to allocate a copy of a buffer), the input array is
2254
+ /// released as it may have been partially moved at the point the error
2255
+ /// occurs.
2256
+ NANOARROW_DLL ArrowErrorCode ArrowArrayMoveShared(struct ArrowArray* array,
2257
+ struct ArrowArray* shared);
2258
+
2259
+ /// \brief Clone a shared ArrowArray
2260
+ ///
2261
+ /// Creates a new ArrowArray whose buffers share the same underlying data as
2262
+ /// the source shared array. The source must have been created by
2263
+ /// ArrowArrayMoveShared() (i.e. all buffers are reference-counted).
2264
+ /// Returns EINVAL if shared is not a shared array.
2265
+ NANOARROW_DLL ArrowErrorCode ArrowArrayCloneShared(struct ArrowArray* shared,
2266
+ struct ArrowArray* array);
2267
+
2137
2268
  /// @}
2138
2269
 
2139
2270
  /// \defgroup nanoarrow-array-view Reading arrays
@@ -22,6 +22,29 @@
22
22
  #include <stdlib.h>
23
23
  #include <string.h>
24
24
 
25
+ // For thread safe shared buffers we need C11 + stdatomic.h
26
+ // Can compile with -DNANOARROW_USE_STDATOMIC=0 or 1 to override
27
+ // automatic detection
28
+ #if !defined(NANOARROW_USE_STDATOMIC)
29
+ #define NANOARROW_USE_STDATOMIC 0
30
+
31
+ // Check for C11
32
+ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
33
+
34
+ // Check for GCC 4.8, which doesn't include stdatomic.h but does
35
+ // not define __STDC_NO_ATOMICS__
36
+ #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5
37
+
38
+ #if !defined(__STDC_NO_ATOMICS__)
39
+ #include <stdatomic.h>
40
+ #undef NANOARROW_USE_STDATOMIC
41
+ #define NANOARROW_USE_STDATOMIC 1
42
+ #endif
43
+ #endif
44
+ #endif
45
+
46
+ #endif
47
+
25
48
  #include "nanoarrow/nanoarrow.h"
26
49
 
27
50
  const char* ArrowNanoarrowVersion(void) { return NANOARROW_VERSION; }
@@ -276,6 +299,225 @@ struct ArrowBufferAllocator ArrowBufferDeallocator(
276
299
  return allocator;
277
300
  }
278
301
 
302
+ #if NANOARROW_USE_STDATOMIC
303
+ struct ArrowSharedBufferPrivate {
304
+ struct ArrowBuffer src;
305
+ atomic_long reference_count;
306
+ };
307
+
308
+ static int64_t ArrowSharedBufferUpdate(struct ArrowSharedBufferPrivate* private_data,
309
+ int delta) {
310
+ int64_t old_count = atomic_fetch_add(&private_data->reference_count, delta);
311
+ return old_count + delta;
312
+ }
313
+
314
+ static void ArrowSharedBufferSet(struct ArrowSharedBufferPrivate* private_data,
315
+ int64_t count) {
316
+ atomic_store(&private_data->reference_count, count);
317
+ }
318
+
319
+ int ArrowSharedBufferIsThreadSafe(void) { return 1; }
320
+
321
+ struct ArrowSharedArrayPrivate {
322
+ struct ArrowArray src;
323
+ atomic_long reference_count;
324
+ };
325
+
326
+ static int64_t ArrowSharedArrayUpdate(struct ArrowSharedArrayPrivate* private_data,
327
+ int delta) {
328
+ int64_t old_count = atomic_fetch_add(&private_data->reference_count, delta);
329
+ return old_count + delta;
330
+ }
331
+
332
+ static void ArrowSharedArraySet(struct ArrowSharedArrayPrivate* private_data,
333
+ int64_t count) {
334
+ atomic_store(&private_data->reference_count, count);
335
+ }
336
+ #else
337
+ struct ArrowSharedBufferPrivate {
338
+ struct ArrowBuffer src;
339
+ int64_t reference_count;
340
+ };
341
+
342
+ static int64_t ArrowSharedBufferUpdate(struct ArrowSharedBufferPrivate* private_data,
343
+ int delta) {
344
+ private_data->reference_count += delta;
345
+ return private_data->reference_count;
346
+ }
347
+
348
+ static void ArrowSharedBufferSet(struct ArrowSharedBufferPrivate* private_data,
349
+ int64_t count) {
350
+ private_data->reference_count = count;
351
+ }
352
+
353
+ int ArrowSharedBufferIsThreadSafe(void) { return 0; }
354
+
355
+ struct ArrowSharedArrayPrivate {
356
+ struct ArrowArray src;
357
+ int64_t reference_count;
358
+ };
359
+
360
+ static int64_t ArrowSharedArrayUpdate(struct ArrowSharedArrayPrivate* private_data,
361
+ int delta) {
362
+ private_data->reference_count += delta;
363
+ return private_data->reference_count;
364
+ }
365
+
366
+ static void ArrowSharedArraySet(struct ArrowSharedArrayPrivate* private_data,
367
+ int64_t count) {
368
+ private_data->reference_count = count;
369
+ }
370
+ #endif
371
+
372
+ static void ArrowSharedBufferFree(struct ArrowBufferAllocator* allocator, uint8_t* ptr,
373
+ int64_t size) {
374
+ NANOARROW_UNUSED(allocator);
375
+ NANOARROW_UNUSED(ptr);
376
+ NANOARROW_UNUSED(size);
377
+
378
+ struct ArrowSharedBufferPrivate* private_data =
379
+ (struct ArrowSharedBufferPrivate*)allocator->private_data;
380
+
381
+ if (ArrowSharedBufferUpdate(private_data, -1) == 0) {
382
+ ArrowBufferReset(&private_data->src);
383
+ ArrowFree(private_data);
384
+ }
385
+ }
386
+
387
+ static void ArrowSharedArrayBufferFree(struct ArrowBufferAllocator* allocator,
388
+ uint8_t* ptr, int64_t size) {
389
+ NANOARROW_UNUSED(ptr);
390
+ NANOARROW_UNUSED(size);
391
+
392
+ struct ArrowSharedArrayPrivate* private_data =
393
+ (struct ArrowSharedArrayPrivate*)allocator->private_data;
394
+
395
+ if (ArrowSharedArrayUpdate(private_data, -1) == 0) {
396
+ if (private_data->src.release != NULL) {
397
+ ArrowArrayRelease(&private_data->src);
398
+ }
399
+ ArrowFree(private_data);
400
+ }
401
+ }
402
+
403
+ ArrowErrorCode ArrowSharedBufferInit(struct ArrowBuffer* shared,
404
+ struct ArrowBuffer* src) {
405
+ if (src->data == NULL) {
406
+ ArrowBufferMove(src, shared);
407
+ return NANOARROW_OK;
408
+ }
409
+
410
+ struct ArrowSharedBufferPrivate* private_data =
411
+ (struct ArrowSharedBufferPrivate*)ArrowMalloc(
412
+ sizeof(struct ArrowSharedBufferPrivate));
413
+ if (private_data == NULL) {
414
+ return ENOMEM;
415
+ }
416
+
417
+ ArrowBufferMove(src, &private_data->src);
418
+ ArrowSharedBufferSet(private_data, 1);
419
+
420
+ ArrowBufferInit(shared);
421
+ shared->data = private_data->src.data;
422
+ shared->size_bytes = private_data->src.size_bytes;
423
+ // Don't expose any extra capcity from src so that any calls to ArrowBufferAppend
424
+ // on this buffer will fail.
425
+ shared->capacity_bytes = private_data->src.size_bytes;
426
+ shared->allocator = ArrowBufferDeallocator(&ArrowSharedBufferFree, private_data);
427
+ return NANOARROW_OK;
428
+ }
429
+
430
+ int ArrowIsSharedBuffer(struct ArrowBuffer* buffer) {
431
+ return buffer->allocator.free == &ArrowSharedBufferFree ||
432
+ buffer->allocator.free == &ArrowSharedArrayBufferFree;
433
+ }
434
+
435
+ ArrowErrorCode ArrowSharedBufferClone(struct ArrowBuffer* shared,
436
+ struct ArrowBuffer* shared_out) {
437
+ // If the buffer has no data, initialize an empty buffer
438
+ if (shared->data == NULL) {
439
+ ArrowBufferInit(shared_out);
440
+ return NANOARROW_OK;
441
+ }
442
+
443
+ if (shared->allocator.free == &ArrowSharedBufferFree) {
444
+ struct ArrowSharedBufferPrivate* private_data =
445
+ (struct ArrowSharedBufferPrivate*)shared->allocator.private_data;
446
+ ArrowSharedBufferUpdate(private_data, 1);
447
+ memcpy(shared_out, shared, sizeof(struct ArrowBuffer));
448
+ return NANOARROW_OK;
449
+ }
450
+
451
+ if (shared->allocator.free == &ArrowSharedArrayBufferFree) {
452
+ struct ArrowSharedArrayPrivate* private_data =
453
+ (struct ArrowSharedArrayPrivate*)shared->allocator.private_data;
454
+ ArrowSharedArrayUpdate(private_data, 1);
455
+ memcpy(shared_out, shared, sizeof(struct ArrowBuffer));
456
+ return NANOARROW_OK;
457
+ }
458
+
459
+ return EINVAL;
460
+ }
461
+
462
+ ArrowErrorCode ArrowSharedArrayInit(struct ArrowSharedArray* shared,
463
+ struct ArrowArray* src) {
464
+ struct ArrowSharedArrayPrivate* private_data =
465
+ (struct ArrowSharedArrayPrivate*)ArrowMalloc(
466
+ sizeof(struct ArrowSharedArrayPrivate));
467
+ if (private_data == NULL) {
468
+ return ENOMEM;
469
+ }
470
+
471
+ ArrowArrayMove(src, &private_data->src);
472
+ ArrowSharedArraySet(private_data, 1);
473
+ shared->private_data = private_data;
474
+ return NANOARROW_OK;
475
+ }
476
+
477
+ void ArrowSharedArrayRelease(struct ArrowSharedArray* shared) {
478
+ if (shared->private_data == NULL) {
479
+ return;
480
+ }
481
+
482
+ struct ArrowSharedArrayPrivate* private_data =
483
+ (struct ArrowSharedArrayPrivate*)shared->private_data;
484
+
485
+ if (ArrowSharedArrayUpdate(private_data, -1) == 0) {
486
+ if (private_data->src.release != NULL) {
487
+ ArrowArrayRelease(&private_data->src);
488
+ }
489
+ ArrowFree(private_data);
490
+ }
491
+
492
+ shared->private_data = NULL;
493
+ }
494
+
495
+ ArrowErrorCode ArrowSharedArrayBuffer(struct ArrowSharedArray* shared, int64_t i,
496
+ struct ArrowBuffer* out) {
497
+ struct ArrowSharedArrayPrivate* private_data =
498
+ (struct ArrowSharedArrayPrivate*)shared->private_data;
499
+ NANOARROW_DCHECK(i >= 0 && i < private_data->src.n_buffers);
500
+
501
+ ArrowSharedArrayUpdate(private_data, 1);
502
+ ArrowBufferInit(out);
503
+
504
+ if (ArrowArrayIsInternal(&private_data->src)) {
505
+ // The source array was built with nanoarrow, so we can get buffer size info
506
+ struct ArrowBuffer* src = ArrowArrayBuffer(&private_data->src, i);
507
+ out->data = src->data;
508
+ out->size_bytes = src->size_bytes;
509
+ out->capacity_bytes = src->size_bytes;
510
+ } else {
511
+ // Generic C Data Interface array: buffer sizes are not known
512
+ out->data = (uint8_t*)private_data->src.buffers[i];
513
+ out->size_bytes = 0;
514
+ out->capacity_bytes = 0;
515
+ }
516
+
517
+ out->allocator = ArrowBufferDeallocator(&ArrowSharedArrayBufferFree, private_data);
518
+ return NANOARROW_OK;
519
+ }
520
+
279
521
  static const int kInt32DecimalDigits = 9;
280
522
 
281
523
  static const uint64_t kUInt32PowersOfTen[] = {
@@ -578,6 +820,7 @@ ArrowErrorCode ArrowDecimalAppendStringToBuffer(const struct ArrowDecimal* decim
578
820
 
579
821
  #include <errno.h>
580
822
  #include <inttypes.h>
823
+ #include <stdarg.h>
581
824
  #include <stdio.h>
582
825
  #include <stdlib.h>
583
826
  #include <string.h>
@@ -1931,47 +2174,34 @@ ArrowErrorCode ArrowSchemaViewInit(struct ArrowSchemaView* schema_view,
1931
2174
  return NANOARROW_OK;
1932
2175
  }
1933
2176
 
1934
- static int64_t ArrowSchemaTypeToStringInternal(struct ArrowSchemaView* schema_view,
1935
- char* out, int64_t n) {
1936
- const char* type_string = ArrowTypeString(schema_view->type);
1937
- switch (schema_view->type) {
1938
- case NANOARROW_TYPE_DECIMAL32:
1939
- case NANOARROW_TYPE_DECIMAL64:
1940
- case NANOARROW_TYPE_DECIMAL128:
1941
- case NANOARROW_TYPE_DECIMAL256:
1942
- return snprintf(out, n, "%s(%" PRId32 ", %" PRId32 ")", type_string,
1943
- schema_view->decimal_precision, schema_view->decimal_scale);
1944
- case NANOARROW_TYPE_TIMESTAMP:
1945
- return snprintf(out, n, "%s('%s', '%s')", type_string,
1946
- ArrowTimeUnitString(schema_view->time_unit), schema_view->timezone);
1947
- case NANOARROW_TYPE_TIME32:
1948
- case NANOARROW_TYPE_TIME64:
1949
- case NANOARROW_TYPE_DURATION:
1950
- return snprintf(out, n, "%s('%s')", type_string,
1951
- ArrowTimeUnitString(schema_view->time_unit));
1952
- case NANOARROW_TYPE_FIXED_SIZE_BINARY:
1953
- case NANOARROW_TYPE_FIXED_SIZE_LIST:
1954
- return snprintf(out, n, "%s(%" PRId32 ")", type_string, schema_view->fixed_size);
1955
- case NANOARROW_TYPE_SPARSE_UNION:
1956
- case NANOARROW_TYPE_DENSE_UNION:
1957
- return snprintf(out, n, "%s([%s])", type_string, schema_view->union_type_ids);
1958
- default:
1959
- return snprintf(out, n, "%s", type_string);
2177
+ static inline void ArrowSchemaToStringSNPrintF(char** out, int64_t* n_remaining,
2178
+ int64_t* n_chars, const char* fmt, ...) {
2179
+ // With _FORTIFY_SOURCE=3, vsnprintf on a null output warns, so ensure we never pass
2180
+ // a NULL to vsnprintf
2181
+ char tmp_not_null[1];
2182
+ char* out_not_null;
2183
+ size_t out_not_null_size;
2184
+ if (*out == NULL) {
2185
+ out_not_null = tmp_not_null;
2186
+ out_not_null_size = sizeof(tmp_not_null);
2187
+ } else {
2188
+ out_not_null = *out;
2189
+ out_not_null_size = (size_t)*n_remaining;
1960
2190
  }
1961
- }
1962
2191
 
1963
- // Helper for bookkeeping to emulate sprintf()-like behaviour spread
1964
- // among multiple sprintf calls.
1965
- static inline void ArrowToStringLogChars(char** out, int64_t n_chars_last,
1966
- int64_t* n_remaining, int64_t* n_chars) {
2192
+ va_list args;
2193
+ va_start(args, fmt);
2194
+ int n_chars_last = vsnprintf(out_not_null, out_not_null_size, fmt, args);
2195
+ va_end(args);
2196
+
1967
2197
  // In the unlikely snprintf() returning a negative value (encoding error),
1968
2198
  // ensure the result won't cause an out-of-bounds access.
1969
2199
  if (n_chars_last < 0) {
1970
2200
  n_chars_last = 0;
1971
2201
  }
1972
2202
 
1973
- *n_chars += n_chars_last;
1974
2203
  *n_remaining -= n_chars_last;
2204
+ *n_chars += n_chars_last;
1975
2205
 
1976
2206
  // n_remaining is never less than 0
1977
2207
  if (*n_remaining < 0) {
@@ -1984,93 +2214,134 @@ static inline void ArrowToStringLogChars(char** out, int64_t n_chars_last,
1984
2214
  }
1985
2215
  }
1986
2216
 
1987
- int64_t ArrowSchemaToString(const struct ArrowSchema* schema, char* out, int64_t n,
1988
- char recursive) {
2217
+ static void ArrowSchemaTypeToStringInternal(struct ArrowSchemaView* schema_view,
2218
+ char** out, int64_t* n_remaining,
2219
+ int64_t* n_chars) {
2220
+ const char* type_string = ArrowTypeString(schema_view->type);
2221
+ switch (schema_view->type) {
2222
+ case NANOARROW_TYPE_DECIMAL32:
2223
+ case NANOARROW_TYPE_DECIMAL64:
2224
+ case NANOARROW_TYPE_DECIMAL128:
2225
+ case NANOARROW_TYPE_DECIMAL256:
2226
+ ArrowSchemaToStringSNPrintF(
2227
+ out, n_remaining, n_chars, "%s(%" PRId32 ", %" PRId32 ")", type_string,
2228
+ schema_view->decimal_precision, schema_view->decimal_scale);
2229
+ return;
2230
+ case NANOARROW_TYPE_TIMESTAMP:
2231
+ ArrowSchemaToStringSNPrintF(
2232
+ out, n_remaining, n_chars, "%s('%s', '%s')", type_string,
2233
+ ArrowTimeUnitString(schema_view->time_unit), schema_view->timezone);
2234
+ return;
2235
+ case NANOARROW_TYPE_TIME32:
2236
+ case NANOARROW_TYPE_TIME64:
2237
+ case NANOARROW_TYPE_DURATION:
2238
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%s('%s')", type_string,
2239
+ ArrowTimeUnitString(schema_view->time_unit));
2240
+ return;
2241
+ case NANOARROW_TYPE_FIXED_SIZE_BINARY:
2242
+ case NANOARROW_TYPE_FIXED_SIZE_LIST:
2243
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%s(%" PRId32 ")",
2244
+ type_string, schema_view->fixed_size);
2245
+ return;
2246
+ case NANOARROW_TYPE_SPARSE_UNION:
2247
+ case NANOARROW_TYPE_DENSE_UNION:
2248
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%s([%s])", type_string,
2249
+ schema_view->union_type_ids);
2250
+ return;
2251
+ default:
2252
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%s", type_string);
2253
+ return;
2254
+ }
2255
+ }
2256
+
2257
+ static void ArrowSchemaToStringInternal(const struct ArrowSchema* schema, char** out,
2258
+ int64_t* n_remaining, int64_t* n_chars,
2259
+ char recursive) {
1989
2260
  if (schema == NULL) {
1990
- return snprintf(out, n, "[invalid: pointer is null]");
2261
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "[invalid: pointer is null]");
2262
+ return;
1991
2263
  }
1992
2264
 
1993
2265
  if (schema->release == NULL) {
1994
- return snprintf(out, n, "[invalid: schema is released]");
2266
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars,
2267
+ "[invalid: schema is released]");
2268
+ return;
1995
2269
  }
1996
2270
 
1997
2271
  struct ArrowSchemaView schema_view;
1998
2272
  struct ArrowError error;
1999
2273
 
2000
2274
  if (ArrowSchemaViewInit(&schema_view, schema, &error) != NANOARROW_OK) {
2001
- return snprintf(out, n, "[invalid: %s]", ArrowErrorMessage(&error));
2275
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "[invalid: %s]",
2276
+ ArrowErrorMessage(&error));
2277
+ return;
2002
2278
  }
2003
2279
 
2004
2280
  // Extension type and dictionary should include both the top-level type
2005
2281
  // and the storage type.
2006
2282
  int is_extension = schema_view.extension_name.size_bytes > 0;
2007
2283
  int is_dictionary = schema->dictionary != NULL;
2008
- int64_t n_chars = 0;
2009
- int64_t n_chars_last = 0;
2010
2284
 
2011
2285
  // Uncommon but not technically impossible that both are true
2012
2286
  if (is_extension && is_dictionary) {
2013
- n_chars_last = snprintf(
2014
- out, n, "%.*s{dictionary(%s)<", (int)schema_view.extension_name.size_bytes,
2015
- schema_view.extension_name.data, ArrowTypeString(schema_view.storage_type));
2287
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%.*s{dictionary(%s)<",
2288
+ (int)schema_view.extension_name.size_bytes,
2289
+ schema_view.extension_name.data,
2290
+ ArrowTypeString(schema_view.storage_type));
2016
2291
  } else if (is_extension) {
2017
- n_chars_last = snprintf(out, n, "%.*s{", (int)schema_view.extension_name.size_bytes,
2018
- schema_view.extension_name.data);
2292
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "%.*s{",
2293
+ (int)schema_view.extension_name.size_bytes,
2294
+ schema_view.extension_name.data);
2019
2295
  } else if (is_dictionary) {
2020
- n_chars_last =
2021
- snprintf(out, n, "dictionary(%s)<", ArrowTypeString(schema_view.storage_type));
2296
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "dictionary(%s)<",
2297
+ ArrowTypeString(schema_view.storage_type));
2022
2298
  }
2023
2299
 
2024
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2025
-
2026
2300
  if (!is_dictionary) {
2027
- n_chars_last = ArrowSchemaTypeToStringInternal(&schema_view, out, n);
2301
+ ArrowSchemaTypeToStringInternal(&schema_view, out, n_remaining, n_chars);
2028
2302
  } else {
2029
- n_chars_last = ArrowSchemaToString(schema->dictionary, out, n, recursive);
2303
+ ArrowSchemaToStringInternal(schema->dictionary, out, n_remaining, n_chars, recursive);
2030
2304
  }
2031
2305
 
2032
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2033
-
2034
2306
  if (recursive && schema->format[0] == '+') {
2035
- n_chars_last = snprintf(out, n, "<");
2036
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2307
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "<");
2037
2308
 
2038
2309
  for (int64_t i = 0; i < schema->n_children; i++) {
2039
2310
  if (i > 0) {
2040
- n_chars_last = snprintf(out, n, ", ");
2041
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2311
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, ", ");
2042
2312
  }
2043
2313
 
2044
2314
  // ArrowSchemaToStringInternal() will validate the child and print the error,
2045
2315
  // but we need the name first
2046
2316
  if (schema->children[i] != NULL && schema->children[i]->release != NULL &&
2047
2317
  schema->children[i]->name != NULL) {
2048
- n_chars_last = snprintf(out, n, "%s: ", schema->children[i]->name);
2049
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2318
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars,
2319
+ "%s: ", schema->children[i]->name);
2050
2320
  }
2051
2321
 
2052
- n_chars_last = ArrowSchemaToString(schema->children[i], out, n, recursive);
2053
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2322
+ ArrowSchemaToStringInternal(schema->children[i], out, n_remaining, n_chars,
2323
+ recursive);
2054
2324
  }
2055
2325
 
2056
- n_chars_last = snprintf(out, n, ">");
2057
- ArrowToStringLogChars(&out, n_chars_last, &n, &n_chars);
2326
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, ">");
2058
2327
  }
2059
2328
 
2060
2329
  if (is_extension && is_dictionary) {
2061
- n_chars += snprintf(out, n, ">}");
2330
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, ">}");
2062
2331
  } else if (is_extension) {
2063
- n_chars += snprintf(out, n, "}");
2332
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, "}");
2064
2333
  } else if (is_dictionary) {
2065
- n_chars += snprintf(out, n, ">");
2334
+ ArrowSchemaToStringSNPrintF(out, n_remaining, n_chars, ">");
2066
2335
  }
2336
+ }
2067
2337
 
2068
- // Ensure that we always return a positive result
2069
- if (n_chars > 0) {
2070
- return n_chars;
2071
- } else {
2072
- return 0;
2073
- }
2338
+ int64_t ArrowSchemaToString(const struct ArrowSchema* schema, char* out, int64_t n,
2339
+ char recursive) {
2340
+ NANOARROW_DCHECK(n >= 0);
2341
+ NANOARROW_DCHECK(out != NULL || n == 0);
2342
+ int64_t n_chars = 0;
2343
+ ArrowSchemaToStringInternal(schema, &out, &n, &n_chars, recursive);
2344
+ return n_chars;
2074
2345
  }
2075
2346
 
2076
2347
  ArrowErrorCode ArrowMetadataReaderInit(struct ArrowMetadataReader* reader,
@@ -2363,7 +2634,7 @@ static void ArrowArrayReleaseInternal(struct ArrowArray* array) {
2363
2634
  array->release = NULL;
2364
2635
  }
2365
2636
 
2366
- static int ArrowArrayIsInternal(struct ArrowArray* array) {
2637
+ int ArrowArrayIsInternal(struct ArrowArray* array) {
2367
2638
  return array->release == &ArrowArrayReleaseInternal;
2368
2639
  }
2369
2640
 
@@ -2858,6 +3129,172 @@ ArrowErrorCode ArrowArrayFinishBuildingDefault(struct ArrowArray* array,
2858
3129
  return ArrowArrayFinishBuilding(array, NANOARROW_VALIDATION_LEVEL_DEFAULT, error);
2859
3130
  }
2860
3131
 
3132
+ static int ArrowArrayIsShared(struct ArrowArray* array) {
3133
+ if (!ArrowArrayIsInternal(array)) {
3134
+ return 0;
3135
+ }
3136
+
3137
+ for (int64_t i = 0; i < array->n_buffers; i++) {
3138
+ struct ArrowBuffer* buffer = ArrowArrayBuffer(array, i);
3139
+ if (buffer->data != NULL && !ArrowIsSharedBuffer(buffer)) {
3140
+ return 0;
3141
+ }
3142
+ }
3143
+
3144
+ for (int64_t i = 0; i < array->n_children; i++) {
3145
+ if (!ArrowArrayIsShared(array->children[i])) {
3146
+ return 0;
3147
+ }
3148
+ }
3149
+
3150
+ if (array->dictionary != NULL && !ArrowArrayIsShared(array->dictionary)) {
3151
+ return 0;
3152
+ }
3153
+
3154
+ return 1;
3155
+ }
3156
+
3157
+ static ArrowErrorCode ArrowArrayMoveSharedInternal(struct ArrowArray* src,
3158
+ struct ArrowArray* dst) {
3159
+ if (ArrowArrayIsShared(src)) {
3160
+ ArrowArrayMove(src, dst);
3161
+ return NANOARROW_OK;
3162
+ }
3163
+
3164
+ NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromType(dst, NANOARROW_TYPE_UNINITIALIZED));
3165
+
3166
+ // Allocate children and move source children to dst children
3167
+ NANOARROW_RETURN_NOT_OK(ArrowArrayAllocateChildren(dst, src->n_children));
3168
+ for (int64_t i = 0; i < src->n_children; i++) {
3169
+ NANOARROW_RETURN_NOT_OK(
3170
+ ArrowArrayMoveSharedInternal(src->children[i], dst->children[i]));
3171
+ }
3172
+
3173
+ // Allocate dictionary if needed and move source dictionary to dst dictionary
3174
+ if (src->dictionary != NULL) {
3175
+ NANOARROW_RETURN_NOT_OK(ArrowArrayAllocateDictionary(dst));
3176
+ NANOARROW_RETURN_NOT_OK(
3177
+ ArrowArrayMoveSharedInternal(src->dictionary, dst->dictionary));
3178
+ }
3179
+
3180
+ // We might need some more buffers if we are shallowly copying a string/binary view
3181
+ if (src->n_buffers > 3) {
3182
+ if (src->n_buffers > INT_MAX) {
3183
+ return EINVAL;
3184
+ }
3185
+
3186
+ NANOARROW_RETURN_NOT_OK(
3187
+ ArrowArrayAddVariadicBuffers(dst, (int32_t)src->n_buffers - 3));
3188
+ }
3189
+
3190
+ // Move src into a shared array and set dst's buffers using the ref-counted version
3191
+ struct ArrowSharedArray shared_array;
3192
+ NANOARROW_RETURN_NOT_OK(ArrowSharedArrayInit(&shared_array, src));
3193
+
3194
+ for (int64_t i = 0; i < src->n_buffers; i++) {
3195
+ struct ArrowBuffer* dst_buffer = ArrowArrayBuffer(dst, i);
3196
+ ArrowErrorCode result = ArrowSharedArrayBuffer(&shared_array, i, dst_buffer);
3197
+ if (result != NANOARROW_OK) {
3198
+ ArrowSharedArrayRelease(&shared_array);
3199
+ return result;
3200
+ }
3201
+ }
3202
+
3203
+ ArrowSharedArrayRelease(&shared_array);
3204
+
3205
+ dst->n_buffers = src->n_buffers;
3206
+ dst->length = src->length;
3207
+ dst->null_count = src->null_count;
3208
+ dst->offset = src->offset;
3209
+
3210
+ // Flush internal buffer pointers to array->buffers
3211
+ NANOARROW_RETURN_NOT_OK(ArrowArrayFlushInternalPointers(dst));
3212
+
3213
+ return NANOARROW_OK;
3214
+ }
3215
+
3216
+ static ArrowErrorCode ArrowArrayCloneSharedInternal(struct ArrowArray* src,
3217
+ struct ArrowArray* dst) {
3218
+ NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromType(dst, NANOARROW_TYPE_UNINITIALIZED));
3219
+
3220
+ // Allocate children and clone source children to dst children
3221
+ NANOARROW_RETURN_NOT_OK(ArrowArrayAllocateChildren(dst, src->n_children));
3222
+ for (int64_t i = 0; i < src->n_children; i++) {
3223
+ NANOARROW_RETURN_NOT_OK(
3224
+ ArrowArrayCloneSharedInternal(src->children[i], dst->children[i]));
3225
+ }
3226
+
3227
+ // Allocate dictionary if needed and clone source dictionary to dst dictionary
3228
+ if (src->dictionary != NULL) {
3229
+ NANOARROW_RETURN_NOT_OK(ArrowArrayAllocateDictionary(dst));
3230
+ NANOARROW_RETURN_NOT_OK(
3231
+ ArrowArrayCloneSharedInternal(src->dictionary, dst->dictionary));
3232
+ }
3233
+
3234
+ // We might need some more buffers if we are shallowly copying a string/binary view
3235
+ if (src->n_buffers > 3) {
3236
+ if (src->n_buffers > INT_MAX) {
3237
+ return EINVAL;
3238
+ }
3239
+
3240
+ NANOARROW_RETURN_NOT_OK(
3241
+ ArrowArrayAddVariadicBuffers(dst, (int32_t)src->n_buffers - 3));
3242
+ }
3243
+
3244
+ for (int64_t i = 0; i < src->n_buffers; i++) {
3245
+ struct ArrowBuffer* src_buffer = ArrowArrayBuffer(src, i);
3246
+ struct ArrowBuffer* dst_buffer = ArrowArrayBuffer(dst, i);
3247
+ NANOARROW_RETURN_NOT_OK(ArrowSharedBufferClone(src_buffer, dst_buffer));
3248
+ }
3249
+
3250
+ dst->n_buffers = src->n_buffers;
3251
+ dst->length = src->length;
3252
+ dst->null_count = src->null_count;
3253
+ dst->offset = src->offset;
3254
+
3255
+ // Flush internal buffer pointers to array->buffers
3256
+ NANOARROW_RETURN_NOT_OK(ArrowArrayFlushInternalPointers(dst));
3257
+
3258
+ return NANOARROW_OK;
3259
+ }
3260
+
3261
+ ArrowErrorCode ArrowArrayMoveShared(struct ArrowArray* array, struct ArrowArray* shared) {
3262
+ struct ArrowArray tmp;
3263
+ tmp.release = NULL;
3264
+ ArrowErrorCode result = ArrowArrayMoveSharedInternal(array, shared);
3265
+ if (result != NANOARROW_OK) {
3266
+ // On failure, release the temporary output
3267
+ if (tmp.release != NULL) {
3268
+ ArrowArrayRelease(&tmp);
3269
+ }
3270
+
3271
+ // Because this operation may have partially moved the input array at this point
3272
+ // we also have to release it on failure to be predictable. These failures are
3273
+ // usually failed heap allocations and are difficult to trigger in practice.
3274
+ if (array->release != NULL) {
3275
+ ArrowArrayRelease(array);
3276
+ }
3277
+ }
3278
+
3279
+ return result;
3280
+ }
3281
+
3282
+ ArrowErrorCode ArrowArrayCloneShared(struct ArrowArray* shared,
3283
+ struct ArrowArray* array) {
3284
+ if (!ArrowArrayIsShared(shared)) {
3285
+ return EINVAL;
3286
+ }
3287
+
3288
+ struct ArrowArray tmp;
3289
+ tmp.release = NULL;
3290
+ ArrowErrorCode result = ArrowArrayCloneSharedInternal(shared, array);
3291
+ if (result != NANOARROW_OK && tmp.release != NULL) {
3292
+ ArrowArrayRelease(&tmp);
3293
+ }
3294
+
3295
+ return result;
3296
+ }
3297
+
2861
3298
  void ArrowArrayViewInitFromType(struct ArrowArrayView* array_view,
2862
3299
  enum ArrowType storage_type) {
2863
3300
  memset(array_view, 0, sizeof(struct ArrowArrayView));
@@ -3803,10 +4240,26 @@ static int ArrowArrayViewValidateFull(struct ArrowArrayView* array_view,
3803
4240
  NANOARROW_RETURN_NOT_OK(ArrowArrayViewValidateFull(array_view->children[i], error));
3804
4241
  }
3805
4242
 
3806
- // Dictionary validation not implemented
4243
+ // Dictionary index validation
3807
4244
  if (array_view->dictionary != NULL) {
3808
4245
  NANOARROW_RETURN_NOT_OK(ArrowArrayViewValidateFull(array_view->dictionary, error));
3809
- // TODO: validate the indices
4246
+
4247
+ // Validate that all non-null indices are within the dictionary bounds
4248
+ int64_t dictionary_length = array_view->dictionary->length;
4249
+ for (int64_t i = 0; i < array_view->length; i++) {
4250
+ if (ArrowArrayViewIsNull(array_view, i)) {
4251
+ continue;
4252
+ }
4253
+
4254
+ int64_t index = ArrowArrayViewGetIntUnsafe(array_view, i);
4255
+ if (index < 0 || index >= dictionary_length) {
4256
+ ArrowErrorSet(error,
4257
+ "[%" PRId64 "] Expected dictionary index >= 0 and < %" PRId64
4258
+ " but found value %" PRId64,
4259
+ i, dictionary_length, index);
4260
+ return EINVAL;
4261
+ }
4262
+ }
3810
4263
  }
3811
4264
 
3812
4265
  return NANOARROW_OK;
@@ -1,3 +1,3 @@
1
1
  module Nanoarrow
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoarrow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  - !ruby/object:Gem::Version
65
65
  version: '0'
66
66
  requirements: []
67
- rubygems_version: 4.0.14
67
+ rubygems_version: 4.0.20
68
68
  specification_version: 4
69
69
  summary: Zero-dependency Arrow library for Ruby
70
70
  test_files: []