xnd 0.2.0dev6 → 0.2.0dev7
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 +4 -4
- data/README.md +2 -0
- data/Rakefile +1 -1
- data/ext/ruby_xnd/GPATH +0 -0
- data/ext/ruby_xnd/GRTAGS +0 -0
- data/ext/ruby_xnd/GTAGS +0 -0
- data/ext/ruby_xnd/extconf.rb +8 -5
- data/ext/ruby_xnd/gc_guard.c +53 -2
- data/ext/ruby_xnd/gc_guard.h +8 -2
- data/ext/ruby_xnd/include/overflow.h +147 -0
- data/ext/ruby_xnd/include/ruby_xnd.h +62 -0
- data/ext/ruby_xnd/include/xnd.h +590 -0
- data/ext/ruby_xnd/lib/libxnd.a +0 -0
- data/ext/ruby_xnd/lib/libxnd.so +1 -0
- data/ext/ruby_xnd/lib/libxnd.so.0 +1 -0
- data/ext/ruby_xnd/lib/libxnd.so.0.2.0dev3 +0 -0
- data/ext/ruby_xnd/ruby_xnd.c +556 -47
- data/ext/ruby_xnd/ruby_xnd.h +2 -1
- data/ext/ruby_xnd/xnd/Makefile +80 -0
- data/ext/ruby_xnd/xnd/config.h +26 -0
- data/ext/ruby_xnd/xnd/config.h.in +3 -0
- data/ext/ruby_xnd/xnd/config.log +421 -0
- data/ext/ruby_xnd/xnd/config.status +1023 -0
- data/ext/ruby_xnd/xnd/configure +376 -8
- data/ext/ruby_xnd/xnd/configure.ac +48 -7
- data/ext/ruby_xnd/xnd/doc/xnd/index.rst +3 -1
- data/ext/ruby_xnd/xnd/doc/xnd/{types.rst → xnd.rst} +3 -18
- data/ext/ruby_xnd/xnd/libxnd/Makefile +142 -0
- data/ext/ruby_xnd/xnd/libxnd/Makefile.in +43 -3
- data/ext/ruby_xnd/xnd/libxnd/Makefile.vc +19 -3
- data/ext/ruby_xnd/xnd/libxnd/bitmaps.c +42 -3
- data/ext/ruby_xnd/xnd/libxnd/bitmaps.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/bounds.c +366 -0
- data/ext/ruby_xnd/xnd/libxnd/bounds.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/contrib.h +98 -0
- data/ext/ruby_xnd/xnd/libxnd/contrib/bfloat16.h +213 -0
- data/ext/ruby_xnd/xnd/libxnd/copy.c +155 -4
- data/ext/ruby_xnd/xnd/libxnd/copy.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/cuda/cuda_memory.cu +121 -0
- data/ext/ruby_xnd/xnd/libxnd/cuda/cuda_memory.h +58 -0
- data/ext/ruby_xnd/xnd/libxnd/equal.c +195 -7
- data/ext/ruby_xnd/xnd/libxnd/equal.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/inline.h +32 -0
- data/ext/ruby_xnd/xnd/libxnd/libxnd.a +0 -0
- data/ext/ruby_xnd/xnd/libxnd/libxnd.so +1 -0
- data/ext/ruby_xnd/xnd/libxnd/libxnd.so.0 +1 -0
- data/ext/ruby_xnd/xnd/libxnd/libxnd.so.0.2.0dev3 +0 -0
- data/ext/ruby_xnd/xnd/libxnd/shape.c +207 -0
- data/ext/ruby_xnd/xnd/libxnd/shape.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/split.c +2 -2
- data/ext/ruby_xnd/xnd/libxnd/split.o +0 -0
- data/ext/ruby_xnd/xnd/libxnd/tests/Makefile +39 -0
- data/ext/ruby_xnd/xnd/libxnd/xnd.c +613 -91
- data/ext/ruby_xnd/xnd/libxnd/xnd.h +145 -4
- data/ext/ruby_xnd/xnd/libxnd/xnd.o +0 -0
- data/ext/ruby_xnd/xnd/python/test_xnd.py +1125 -50
- data/ext/ruby_xnd/xnd/python/xnd/__init__.py +609 -124
- data/ext/ruby_xnd/xnd/python/xnd/_version.py +1 -0
- data/ext/ruby_xnd/xnd/python/xnd/_xnd.c +1652 -101
- data/ext/ruby_xnd/xnd/python/xnd/libxnd.a +0 -0
- data/ext/ruby_xnd/xnd/python/xnd/libxnd.so +1 -0
- data/ext/ruby_xnd/xnd/python/xnd/libxnd.so.0 +1 -0
- data/ext/ruby_xnd/xnd/python/xnd/libxnd.so.0.2.0dev3 +0 -0
- data/ext/ruby_xnd/xnd/python/xnd/pyxnd.h +1 -1
- data/ext/ruby_xnd/xnd/python/xnd/util.h +25 -0
- data/ext/ruby_xnd/xnd/python/xnd/xnd.h +590 -0
- data/ext/ruby_xnd/xnd/python/xnd_randvalue.py +106 -6
- data/ext/ruby_xnd/xnd/python/xnd_support.py +4 -0
- data/ext/ruby_xnd/xnd/setup.py +46 -4
- data/lib/ruby_xnd.so +0 -0
- data/lib/xnd.rb +39 -3
- data/lib/xnd/version.rb +2 -2
- data/xnd.gemspec +2 -1
- metadata +58 -5
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
ext/ruby_xnd/lib/libxnd.so.0.2.0dev3
|
@@ -0,0 +1 @@
|
|
1
|
+
ext/ruby_xnd/lib/libxnd.so.0.2.0dev3
|
Binary file
|
data/ext/ruby_xnd/ruby_xnd.c
CHANGED
@@ -37,6 +37,10 @@
|
|
37
37
|
#include "ruby_xnd_internal.h"
|
38
38
|
#include "xnd.h"
|
39
39
|
|
40
|
+
#define XND_CHECK_NUMERIC(obj) Check_Type(obj, T_FIXNUM); \
|
41
|
+
Check_Type(obj, T_BIGNUM); Check_Type(obj, T_RATIONAL); \
|
42
|
+
Check_Type(obj, T_RATIONAL);
|
43
|
+
|
40
44
|
VALUE cRubyXND;
|
41
45
|
VALUE cXND;
|
42
46
|
static VALUE cRubyXND_MBlock;
|
@@ -47,6 +51,8 @@ static VALUE rb_eValueError;
|
|
47
51
|
|
48
52
|
VALUE mRubyXND_GCGuard;
|
49
53
|
|
54
|
+
static VALUE seterr(ndt_context_t *ctx);
|
55
|
+
|
50
56
|
/****************************************************************************/
|
51
57
|
/* Error handling */
|
52
58
|
/****************************************************************************/
|
@@ -108,6 +114,7 @@ MemoryBlockObject_dfree(void *self)
|
|
108
114
|
{
|
109
115
|
MemoryBlockObject *mblock = (MemoryBlockObject*)self;
|
110
116
|
|
117
|
+
rb_xnd_gc_guard_unregister_mblock_type(mblock);
|
111
118
|
xnd_del(mblock->xnd);
|
112
119
|
mblock->xnd = NULL;
|
113
120
|
xfree(mblock);
|
@@ -159,19 +166,21 @@ mblock_allocate(void)
|
|
159
166
|
|
160
167
|
/* Create empty mblock with no data. */
|
161
168
|
static VALUE
|
162
|
-
mblock_empty(VALUE type)
|
169
|
+
mblock_empty(VALUE type, uint32_t flags)
|
163
170
|
{
|
164
171
|
NDT_STATIC_CONTEXT(ctx);
|
165
172
|
MemoryBlockObject *mblock_p;
|
173
|
+
const ndt_t * ndt_p;
|
166
174
|
|
167
175
|
if (!rb_ndtypes_check_type(type)) {
|
168
176
|
rb_raise(rb_eArgError, "require NDT object to create mblock in mblock_empty.");
|
169
177
|
}
|
170
178
|
|
171
179
|
mblock_p = mblock_alloc();
|
172
|
-
|
173
|
-
|
174
|
-
|
180
|
+
ndt_p = rb_ndtypes_const_ndt(type);
|
181
|
+
// ndt_incref(ndt_p);
|
182
|
+
|
183
|
+
mblock_p->xnd = xnd_empty_from_type(ndt_p, XND_OWN_EMBEDDED|flags, &ctx);
|
175
184
|
if (mblock_p->xnd == NULL) {
|
176
185
|
rb_raise(rb_eValueError, "cannot create mblock object from given type.");
|
177
186
|
}
|
@@ -299,6 +308,42 @@ get_uint(VALUE data, uint64_t max)
|
|
299
308
|
return x;
|
300
309
|
}
|
301
310
|
|
311
|
+
static int
|
312
|
+
union_tag_and_value_from_tuple(uint8_t *tag, VALUE *value, const ndt_t *t,
|
313
|
+
VALUE tuple)
|
314
|
+
{
|
315
|
+
VALUE name;
|
316
|
+
int64_t i;
|
317
|
+
char *sname;
|
318
|
+
|
319
|
+
assert(t->tag == Union);
|
320
|
+
|
321
|
+
if (RARRAY_LEN(tuple) != 2) {
|
322
|
+
rb_raise(rb_eValueError,
|
323
|
+
"unions are represented by a tuple (tag, value), where tag is a string.");
|
324
|
+
}
|
325
|
+
|
326
|
+
name = rb_ary_entry(tuple, 0);
|
327
|
+
|
328
|
+
Check_Type(name, T_STRING);
|
329
|
+
|
330
|
+
for (i = 0; i < t->Union.ntags; ++i) {
|
331
|
+
sname = RSTRING_PTR(name);
|
332
|
+
if (strcmp(sname, t->Union.tags[i]) == 0) {
|
333
|
+
break;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
337
|
+
if (i == t->Union.ntags) {
|
338
|
+
rb_raise(rb_eValueError, "%s is not a valid tag name.", sname);
|
339
|
+
}
|
340
|
+
|
341
|
+
*tag = (uint8_t)i;
|
342
|
+
*value = rb_ary_entry(tuple, 1);
|
343
|
+
|
344
|
+
return 0;
|
345
|
+
}
|
346
|
+
|
302
347
|
/* Initialize an mblock object with data. */
|
303
348
|
static int
|
304
349
|
mblock_init(xnd_t * const x, VALUE data)
|
@@ -430,6 +475,26 @@ mblock_init(xnd_t * const x, VALUE data)
|
|
430
475
|
return 0;
|
431
476
|
}
|
432
477
|
|
478
|
+
case Union : {
|
479
|
+
VALUE tmp;
|
480
|
+
uint8_t tag;
|
481
|
+
|
482
|
+
if (union_tag_and_value_from_tuple(&tag, &tmp, t, data) < 0) {
|
483
|
+
return -1;
|
484
|
+
}
|
485
|
+
|
486
|
+
xnd_clear(x, XND_OWN_EMBEDDED);
|
487
|
+
XND_UNION_TAG(x->ptr) = tag;
|
488
|
+
|
489
|
+
xnd_t next = xnd_union_next(x, &ctx);
|
490
|
+
if (next.ptr == NULL) {
|
491
|
+
seterr(&ctx);
|
492
|
+
raise_error();
|
493
|
+
}
|
494
|
+
|
495
|
+
return mblock_init(&next, tmp);
|
496
|
+
}
|
497
|
+
|
433
498
|
case Ref: {
|
434
499
|
xnd_t next = xnd_ref_next(x, &ctx);
|
435
500
|
if (next.ptr == NULL) {
|
@@ -831,13 +896,13 @@ mblock_init(xnd_t * const x, VALUE data)
|
|
831
896
|
* @param data - Data as a Ruby object.
|
832
897
|
*/
|
833
898
|
static VALUE
|
834
|
-
mblock_from_typed_value(VALUE type, VALUE data)
|
899
|
+
mblock_from_typed_value(VALUE type, VALUE data, int32_t flags)
|
835
900
|
{
|
836
901
|
VALUE mblock;
|
837
902
|
MemoryBlockObject *mblock_p;
|
838
903
|
|
839
|
-
mblock = mblock_empty(type);
|
840
|
-
GET_MBLOCK(mblock, mblock_p);
|
904
|
+
mblock = mblock_empty(type, flags);
|
905
|
+
GET_MBLOCK(mblock, mblock_p);
|
841
906
|
mblock_init(&mblock_p->xnd->master, data);
|
842
907
|
|
843
908
|
return mblock;
|
@@ -854,6 +919,11 @@ typedef struct XndObject {
|
|
854
919
|
} XndObject;
|
855
920
|
|
856
921
|
#define XND(xnd_p) (&(((XndObject *)xnd_p)->xnd))
|
922
|
+
#define TYPE_OWNER(xnd_p) ((((XndObject *)xnd_p)->type))
|
923
|
+
#define XND_TYPE(xnd_p) (((XndObject *)xnd_p)->xnd.type)
|
924
|
+
#define XND_INDEX(xnd_p) (((XndObject *)xnd_p)->xnd.index)
|
925
|
+
#define XND_PTR(xnd_p) (((XndObject *)xnd_p)->xnd.ptr)
|
926
|
+
|
857
927
|
#define XND_CHECK_TYPE(xnd) (CLASS_OF(xnd) == cXND)
|
858
928
|
#define GET_XND(obj, xnd_p) do { \
|
859
929
|
TypedData_Get_Struct((obj), XndObject, \
|
@@ -900,7 +970,8 @@ XndObject_dfree(void *self)
|
|
900
970
|
{
|
901
971
|
XndObject *xnd = (XndObject*)self;
|
902
972
|
|
903
|
-
|
973
|
+
rb_xnd_gc_guard_unregister_xnd_mblock(xnd);
|
974
|
+
rb_xnd_gc_guard_unregister_xnd_type(xnd);
|
904
975
|
xfree(xnd);
|
905
976
|
}
|
906
977
|
|
@@ -954,18 +1025,57 @@ RubyXND_allocate(VALUE klass)
|
|
954
1025
|
return WRAP_XND(klass, xnd);
|
955
1026
|
}
|
956
1027
|
|
1028
|
+
static uint32_t
|
1029
|
+
device_flags(VALUE array)
|
1030
|
+
{
|
1031
|
+
VALUE device, no;
|
1032
|
+
|
1033
|
+
Check_Type(array, T_ARRAY);
|
1034
|
+
if (RARRAY_LEN(array) != 2) {
|
1035
|
+
rb_raise(rb_eTypeError, "device argument must be of the form (device_name, device_no).");
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
device = rb_ary_entry(array, 0);
|
1039
|
+
Check_Type(device, T_STRING);
|
1040
|
+
if (RTEST(rb_funcall(device, rb_intern("=="), 1, rb_str_new_literal("cuda")))) {
|
1041
|
+
rb_raise(rb_eValueError, "currently only 'cuda' is supported as a device name.");
|
1042
|
+
}
|
1043
|
+
|
1044
|
+
no = rb_ary_entry(array, 1);
|
1045
|
+
Check_Type(no, T_FIXNUM);
|
1046
|
+
if (FIX2NUM(no) != -1) {
|
1047
|
+
rb_raise(rb_eValueError, "currently only 'cuda:managed' is supported as a device.");
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
return XND_CUDA_MANAGED;
|
1051
|
+
}
|
1052
|
+
|
957
1053
|
/* Initialize a RubyXND object. */
|
958
1054
|
static VALUE
|
959
|
-
RubyXND_initialize(VALUE self, VALUE type, VALUE data)
|
1055
|
+
RubyXND_initialize(VALUE self, VALUE type, VALUE data, VALUE device)
|
960
1056
|
{
|
961
1057
|
VALUE mblock;
|
1058
|
+
MemoryBlockObject *mblock_p;
|
962
1059
|
XndObject *xnd_p;
|
1060
|
+
uint32_t flags = 0;
|
963
1061
|
|
964
|
-
|
965
|
-
|
1062
|
+
if (device != Qnil) {
|
1063
|
+
flags = device_flags(device);
|
1064
|
+
if (flags == UINT32_MAX) {
|
1065
|
+
rb_raise(rb_eValueError, "device ID cannot be handled.");
|
1066
|
+
}
|
1067
|
+
}
|
966
1068
|
|
1069
|
+
mblock = mblock_from_typed_value(type, data, flags);
|
1070
|
+
GET_MBLOCK(mblock, mblock_p);
|
1071
|
+
|
1072
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
1073
|
+
|
1074
|
+
GET_XND(self, xnd_p);
|
967
1075
|
XND_from_mblock(xnd_p, mblock);
|
968
|
-
|
1076
|
+
|
1077
|
+
rb_xnd_gc_guard_register_xnd_mblock(xnd_p, mblock);
|
1078
|
+
rb_xnd_gc_guard_register_xnd_type(xnd_p, type);
|
969
1079
|
|
970
1080
|
#ifdef XND_DEBUG
|
971
1081
|
assert(XND(xnd_p)->type);
|
@@ -990,6 +1100,16 @@ XND_get_size(VALUE xnd)
|
|
990
1100
|
|
991
1101
|
/*************************** object properties ********************************/
|
992
1102
|
|
1103
|
+
static VALUE
|
1104
|
+
XND_dtype(VALUE self)
|
1105
|
+
{
|
1106
|
+
XndObject *self_p;
|
1107
|
+
GET_XND(self, self_p);
|
1108
|
+
const ndt_t *dtype = ndt_dtype(XND_TYPE(self_p));
|
1109
|
+
|
1110
|
+
return rb_ndtypes_from_type(dtype);
|
1111
|
+
}
|
1112
|
+
|
993
1113
|
/* Return the ndtypes object of this xnd object. */
|
994
1114
|
static VALUE
|
995
1115
|
XND_type(VALUE self)
|
@@ -998,7 +1118,6 @@ XND_type(VALUE self)
|
|
998
1118
|
|
999
1119
|
GET_XND(self, xnd_p);
|
1000
1120
|
|
1001
|
-
|
1002
1121
|
return xnd_p->type;
|
1003
1122
|
}
|
1004
1123
|
|
@@ -1077,6 +1196,25 @@ _XND_value(const xnd_t * const x, const int64_t maxshape)
|
|
1077
1196
|
|
1078
1197
|
return array;
|
1079
1198
|
}
|
1199
|
+
|
1200
|
+
case VarDimElem: {
|
1201
|
+
int64_t start, step, shape;
|
1202
|
+
|
1203
|
+
shape = ndt_var_indices(&start, &step, t, x->index, &ctx);
|
1204
|
+
if (shape < 0) {
|
1205
|
+
seterr(&ctx);
|
1206
|
+
raise_error();
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
const int64_t i = adjust_index(t->VarDimElem.index, shape, &ctx);
|
1210
|
+
if (i < 0) {
|
1211
|
+
seterr(&ctx);
|
1212
|
+
raise_error();
|
1213
|
+
}
|
1214
|
+
|
1215
|
+
const xnd_t next = xnd_var_dim_next(x, start, step, i);
|
1216
|
+
return _XND_value(&next, maxshape);
|
1217
|
+
}
|
1080
1218
|
|
1081
1219
|
case Tuple: {
|
1082
1220
|
VALUE tuple, v;
|
@@ -1138,6 +1276,27 @@ _XND_value(const xnd_t * const x, const int64_t maxshape)
|
|
1138
1276
|
return hash;
|
1139
1277
|
}
|
1140
1278
|
|
1279
|
+
case Union: {
|
1280
|
+
VALUE array, tag, v;
|
1281
|
+
|
1282
|
+
array = rb_ary_new2(2);
|
1283
|
+
const uint8_t i = XND_UNION_TAG(x->ptr);
|
1284
|
+
tag = rb_str_new2(t->Union.tags[i]);
|
1285
|
+
|
1286
|
+
rb_ary_store(array, 0, tag);
|
1287
|
+
|
1288
|
+
const xnd_t next = xnd_union_next(x, &ctx);
|
1289
|
+
if (next.ptr == NULL) {
|
1290
|
+
seterr(&ctx);
|
1291
|
+
raise_error();
|
1292
|
+
}
|
1293
|
+
v = _XND_value(&next, maxshape);
|
1294
|
+
|
1295
|
+
rb_ary_store(array, 1, v);
|
1296
|
+
|
1297
|
+
return array;
|
1298
|
+
}
|
1299
|
+
|
1141
1300
|
case Ref: {
|
1142
1301
|
xnd_t next = xnd_ref_next(x, &ctx);
|
1143
1302
|
if (next.ptr == NULL) {
|
@@ -1309,8 +1468,8 @@ _XND_value(const xnd_t * const x, const int64_t maxshape)
|
|
1309
1468
|
}
|
1310
1469
|
|
1311
1470
|
case String: {
|
1312
|
-
const char *s =
|
1313
|
-
size_t size =
|
1471
|
+
const char *s = XND_STRING_DATA(x->ptr);
|
1472
|
+
size_t size = strlen(s);
|
1314
1473
|
|
1315
1474
|
return rb_utf8_str_new(s, size);
|
1316
1475
|
}
|
@@ -1403,9 +1562,12 @@ static VALUE
|
|
1403
1562
|
RubyXND_view_move_type(XndObject *src_p, xnd_t *x)
|
1404
1563
|
{
|
1405
1564
|
XndObject *view_p;
|
1565
|
+
MemoryBlockObject* mblock_p;
|
1406
1566
|
VALUE type, view;
|
1407
1567
|
|
1408
|
-
type =
|
1568
|
+
type = rb_ndtypes_from_type(x->type);
|
1569
|
+
ndt_decref(x->type);
|
1570
|
+
|
1409
1571
|
view = XndObject_alloc();
|
1410
1572
|
GET_XND(view, view_p);
|
1411
1573
|
|
@@ -1413,7 +1575,11 @@ RubyXND_view_move_type(XndObject *src_p, xnd_t *x)
|
|
1413
1575
|
view_p->type = type;
|
1414
1576
|
view_p->xnd = *x;
|
1415
1577
|
|
1416
|
-
|
1578
|
+
GET_MBLOCK(view_p->mblock, mblock_p);
|
1579
|
+
|
1580
|
+
rb_xnd_gc_guard_register_xnd_type(view_p, type);
|
1581
|
+
rb_xnd_gc_guard_register_xnd_mblock(view_p, view_p->mblock);
|
1582
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
1417
1583
|
|
1418
1584
|
return view;
|
1419
1585
|
}
|
@@ -1598,6 +1764,34 @@ XND_spaceship(VALUE self, VALUE other)
|
|
1598
1764
|
return Qnil;
|
1599
1765
|
}
|
1600
1766
|
|
1767
|
+
static VALUE
|
1768
|
+
XND_lt(VALUE self, VALUE other)
|
1769
|
+
{
|
1770
|
+
rb_raise(rb_eNotImpError, "< not implemented yet.");
|
1771
|
+
return Qnil;
|
1772
|
+
}
|
1773
|
+
|
1774
|
+
static VALUE
|
1775
|
+
XND_lteq(VALUE self, VALUE other)
|
1776
|
+
{
|
1777
|
+
rb_raise(rb_eNotImpError, "<= not implemented yet.");
|
1778
|
+
return Qnil;
|
1779
|
+
}
|
1780
|
+
|
1781
|
+
static VALUE
|
1782
|
+
XND_gt(VALUE self, VALUE other)
|
1783
|
+
{
|
1784
|
+
rb_raise(rb_eNotImpError, "> not implemented yet.");
|
1785
|
+
return Qnil;
|
1786
|
+
}
|
1787
|
+
|
1788
|
+
static VALUE
|
1789
|
+
XND_gteq(VALUE self, VALUE other)
|
1790
|
+
{
|
1791
|
+
rb_raise(rb_eNotImpError, ">= not implemented yet.");
|
1792
|
+
return Qnil;
|
1793
|
+
}
|
1794
|
+
|
1601
1795
|
/* XND#strict_equal */
|
1602
1796
|
static VALUE
|
1603
1797
|
XND_strict_equal(VALUE self, VALUE other)
|
@@ -1662,6 +1856,26 @@ _XND_size(const xnd_t *x)
|
|
1662
1856
|
return safe_downcast(shape);
|
1663
1857
|
}
|
1664
1858
|
|
1859
|
+
case VarDimElem: {
|
1860
|
+
NDT_STATIC_CONTEXT(ctx);
|
1861
|
+
int64_t start, step, shape;
|
1862
|
+
|
1863
|
+
shape = ndt_var_indices(&start, &step, t, x->index, &ctx);
|
1864
|
+
if (shape < 0) {
|
1865
|
+
seterr(&ctx);
|
1866
|
+
raise_error();
|
1867
|
+
}
|
1868
|
+
|
1869
|
+
const int64_t i = adjust_index(t->VarDimElem.index, shape, &ctx);
|
1870
|
+
if (i < 0) {
|
1871
|
+
seterr(&ctx);
|
1872
|
+
raise_error();
|
1873
|
+
}
|
1874
|
+
|
1875
|
+
const xnd_t next = xnd_var_dim_next(x, start, step, i);
|
1876
|
+
return _XND_size(&next);
|
1877
|
+
}
|
1878
|
+
|
1665
1879
|
case Tuple: {
|
1666
1880
|
return safe_downcast(t->Tuple.shape);
|
1667
1881
|
}
|
@@ -1670,6 +1884,16 @@ _XND_size(const xnd_t *x)
|
|
1670
1884
|
return safe_downcast(t->Record.shape);
|
1671
1885
|
}
|
1672
1886
|
|
1887
|
+
case Union: {
|
1888
|
+
const xnd_t next = xnd_union_next(x, &ctx);
|
1889
|
+
if (next.ptr == NULL) {
|
1890
|
+
seterr(&ctx);
|
1891
|
+
raise_error();
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
return _XND_size(&next);
|
1895
|
+
}
|
1896
|
+
|
1673
1897
|
case Ref: {
|
1674
1898
|
const xnd_t next = xnd_ref_next(x, &ctx);
|
1675
1899
|
if (next.ptr == NULL) {
|
@@ -1743,19 +1967,11 @@ XND_array_store(int argc, VALUE *argv, VALUE self)
|
|
1743
1967
|
rb_raise(rb_eIndexError, "wrong kind of key in []=");
|
1744
1968
|
}
|
1745
1969
|
|
1746
|
-
|
1747
|
-
x = xnd_multikey(&self_p->xnd, indices, len, &ctx);
|
1748
|
-
free_type = 1;
|
1749
|
-
}
|
1750
|
-
else {
|
1751
|
-
x = xnd_subtree(&self_p->xnd, indices, len, &ctx);
|
1752
|
-
}
|
1753
|
-
|
1970
|
+
x = xnd_subscript(&self_p->xnd, indices, len, &ctx);
|
1754
1971
|
if (x.ptr == NULL) {
|
1755
1972
|
seterr(&ctx);
|
1756
1973
|
raise_error();
|
1757
1974
|
}
|
1758
|
-
|
1759
1975
|
value = argv[argc-1];
|
1760
1976
|
|
1761
1977
|
if (XND_CHECK_TYPE(value)) {
|
@@ -1771,10 +1987,7 @@ XND_array_store(int argc, VALUE *argv, VALUE self)
|
|
1771
1987
|
else {
|
1772
1988
|
ret = mblock_init(&x, value);
|
1773
1989
|
}
|
1774
|
-
|
1775
|
-
if (free_type) {
|
1776
|
-
ndt_del((ndt_t *)x.type);
|
1777
|
-
}
|
1990
|
+
ndt_decref(x.type);
|
1778
1991
|
|
1779
1992
|
return value;
|
1780
1993
|
}
|
@@ -1807,22 +2020,299 @@ XND_short_value(VALUE self, VALUE maxshape)
|
|
1807
2020
|
}
|
1808
2021
|
}
|
1809
2022
|
|
2023
|
+
/* Implementation of XND#_transpose */
|
2024
|
+
static VALUE
|
2025
|
+
XND_transpose(VALUE self, VALUE permute) {
|
2026
|
+
NDT_STATIC_CONTEXT(ctx);
|
2027
|
+
int p[NDT_MAX_ARGS];
|
2028
|
+
const ndt_t *t;
|
2029
|
+
xnd_t x;
|
2030
|
+
XndObject *self_p;
|
2031
|
+
|
2032
|
+
GET_XND(self, self_p);
|
2033
|
+
|
2034
|
+
if (permute != Qnil) {
|
2035
|
+
Check_Type(permute, T_ARRAY);
|
2036
|
+
const size_t len = RARRAY_LEN(permute);
|
2037
|
+
|
2038
|
+
if (len > NDT_MAX_ARGS) {
|
2039
|
+
rb_raise(rb_eValueError, "permutation list is too long.");
|
2040
|
+
}
|
2041
|
+
|
2042
|
+
for (int i = 0; i < len; i++) {
|
2043
|
+
VALUE v_obj = rb_ary_entry(permute, i);
|
2044
|
+
Check_Type(v_obj, T_FIXNUM);
|
2045
|
+
int v = FIX2INT(v_obj);
|
2046
|
+
|
2047
|
+
if (v < 0 || v > INT_MAX) {
|
2048
|
+
rb_raise(rb_eValueError, "permutation index is out of bounds.");
|
2049
|
+
}
|
2050
|
+
p[i] = (int)v;
|
2051
|
+
}
|
2052
|
+
|
2053
|
+
t = ndt_transpose(XND_TYPE(self_p), p, (int)len, &ctx);
|
2054
|
+
}
|
2055
|
+
else {
|
2056
|
+
t = ndt_transpose(XND_TYPE(self_p), NULL, 0, &ctx);
|
2057
|
+
}
|
2058
|
+
|
2059
|
+
if (t == NULL) {
|
2060
|
+
seterr(&ctx);
|
2061
|
+
raise_error();
|
2062
|
+
}
|
2063
|
+
|
2064
|
+
x = *XND(self_p);
|
2065
|
+
x.type = t;
|
2066
|
+
|
2067
|
+
return RubyXND_view_move_type(self_p, &x);
|
2068
|
+
}
|
2069
|
+
|
2070
|
+
/* XND#_reshape */
|
2071
|
+
static VALUE
|
2072
|
+
XND_reshape(VALUE self, VALUE obj_shape, VALUE order)
|
2073
|
+
{
|
2074
|
+
NDT_STATIC_CONTEXT(ctx);
|
2075
|
+
int64_t shape[NDT_MAX_DIM];
|
2076
|
+
XndObject *self_p;
|
2077
|
+
char ord = 'C';
|
2078
|
+
size_t n;
|
2079
|
+
|
2080
|
+
if (order != Qnil) {
|
2081
|
+
const char *c = RSTRING_PTR(order);
|
2082
|
+
if (strlen(c) != 1) {
|
2083
|
+
rb_raise(rb_eValueError, "'order' argument must be a 'C', 'F' or 'A'.");
|
2084
|
+
}
|
2085
|
+
ord = c[0];
|
2086
|
+
}
|
2087
|
+
|
2088
|
+
Check_Type(obj_shape, T_ARRAY);
|
2089
|
+
|
2090
|
+
n = RARRAY_LEN(obj_shape);
|
2091
|
+
if (n > NDT_MAX_DIM) {
|
2092
|
+
rb_raise(rb_eValueError, "too many dimensions.");
|
2093
|
+
}
|
2094
|
+
|
2095
|
+
for (int i = 0; i < n; ++i) {
|
2096
|
+
shape[i] = FIX2INT(rb_ary_entry(obj_shape, i));
|
2097
|
+
if (shape[i] < 0) {
|
2098
|
+
rb_raise(rb_eValueError, "negative dimension size.");
|
2099
|
+
}
|
2100
|
+
}
|
2101
|
+
|
2102
|
+
GET_XND(self, self_p);
|
2103
|
+
xnd_t view = xnd_reshape(XND(self_p), shape, (int)n, ord, &ctx);
|
2104
|
+
if (xnd_err_occurred(&view)) {
|
2105
|
+
seterr(&ctx);
|
2106
|
+
raise_error();
|
2107
|
+
}
|
2108
|
+
|
2109
|
+
return RubyXND_view_move_type(self_p, &view);
|
2110
|
+
}
|
2111
|
+
|
2112
|
+
/* XND#copy_contiguous */
|
2113
|
+
static VALUE
|
2114
|
+
XND_copy_contiguous(int argc, VALUE *argv, VALUE self)
|
2115
|
+
{
|
2116
|
+
NDT_STATIC_CONTEXT(ctx);
|
2117
|
+
XndObject *self_p, *dest_p;
|
2118
|
+
NdtObject *dtype_p;
|
2119
|
+
VALUE dtype;
|
2120
|
+
VALUE dest;
|
2121
|
+
const ndt_t *t;
|
2122
|
+
MemoryBlockObject *self_mblock_p;
|
2123
|
+
|
2124
|
+
if (argc == 1) {
|
2125
|
+
dtype = argv[0];
|
2126
|
+
}
|
2127
|
+
else if (argc == 0) {
|
2128
|
+
dtype = Qnil;
|
2129
|
+
}
|
2130
|
+
else {
|
2131
|
+
rb_raise(rb_eArgError, "copy_contiguous can accept only one arg for dtype.");
|
2132
|
+
}
|
2133
|
+
|
2134
|
+
GET_XND(self, self_p);
|
2135
|
+
|
2136
|
+
if (dtype != Qnil) {
|
2137
|
+
if (!rb_ndtypes_check_type(dtype)) {
|
2138
|
+
rb_raise(rb_eTypeError, "dtype must be of type ndtypes.");
|
2139
|
+
}
|
2140
|
+
t = ndt_copy_contiguous_dtype(XND_TYPE(self_p),
|
2141
|
+
rb_ndtypes_const_ndt(dtype),
|
2142
|
+
XND_INDEX(self_p), &ctx);
|
2143
|
+
}
|
2144
|
+
else {
|
2145
|
+
t = ndt_copy_contiguous(XND_TYPE(self_p), XND_INDEX(self_p), &ctx);
|
2146
|
+
}
|
2147
|
+
|
2148
|
+
if (t == NULL) {
|
2149
|
+
seterr(&ctx);
|
2150
|
+
}
|
2151
|
+
|
2152
|
+
dest = rb_xnd_empty_from_type(t, 0);
|
2153
|
+
ndt_decref(t);
|
2154
|
+
|
2155
|
+
GET_XND(dest, dest_p);
|
2156
|
+
GET_MBLOCK(self_p->mblock, self_mblock_p);
|
2157
|
+
|
2158
|
+
if (xnd_copy(XND(dest_p), XND(self_p), self_mblock_p->xnd->flags, &ctx) < 0) {
|
2159
|
+
seterr(&ctx);
|
2160
|
+
raise_error();
|
2161
|
+
}
|
2162
|
+
|
2163
|
+
return dest;
|
2164
|
+
}
|
2165
|
+
|
2166
|
+
static VALUE
|
2167
|
+
XND_serialize(VALUE self)
|
2168
|
+
{
|
2169
|
+
NDT_STATIC_CONTEXT(ctx);
|
2170
|
+
bool overflow = false;
|
2171
|
+
const xnd_t *x;
|
2172
|
+
const ndt_t* t;
|
2173
|
+
VALUE result;
|
2174
|
+
char *cp, *s;
|
2175
|
+
int64_t tlen, size;
|
2176
|
+
XndObject *self_p;
|
2177
|
+
|
2178
|
+
GET_XND(self, self_p);
|
2179
|
+
x = XND(self_p);
|
2180
|
+
t = XND_TYPE(self_p);
|
2181
|
+
|
2182
|
+
if (!ndt_is_pointer_free(t)) {
|
2183
|
+
rb_raise(rb_eNotImpError, "serializing memory blocks with pointers is not implemented.");
|
2184
|
+
}
|
2185
|
+
|
2186
|
+
if (ndt_is_optional(t) || ndt_subtree_is_optional(t)) {
|
2187
|
+
rb_raise(rb_eNotImpError, "serializing bitmaps is not implemented.");
|
2188
|
+
}
|
2189
|
+
|
2190
|
+
if (!ndt_is_c_contiguous(t) && !ndt_is_f_contiguous(t) &&
|
2191
|
+
!ndt_is_var_contiguous(t)) {
|
2192
|
+
rb_raise(rb_eNotImpError, "serializing non-contiguos memory blocks is not implemented.");
|
2193
|
+
}
|
2194
|
+
|
2195
|
+
tlen = ndt_serialize(&s, t, &ctx);
|
2196
|
+
if (tlen < 0) {
|
2197
|
+
seterr(&ctx);
|
2198
|
+
raise_error();
|
2199
|
+
}
|
2200
|
+
|
2201
|
+
size = ADDi64(t->datasize, tlen, &overflow);
|
2202
|
+
size = ADDi64(size, 8, &overflow);
|
2203
|
+
if (overflow) {
|
2204
|
+
ndt_free(s);
|
2205
|
+
/* FIXME: maybe create a new OverflowError for this. */
|
2206
|
+
rb_raise(rb_eTypeError, "too large to serialize.");
|
2207
|
+
}
|
2208
|
+
|
2209
|
+
result = rb_str_new(NULL, size);
|
2210
|
+
cp = RSTRING_PTR(result);
|
2211
|
+
|
2212
|
+
char *ptr = x->ptr;
|
2213
|
+
if (t->ndim != 0) {
|
2214
|
+
ptr = x->ptr + x->index * t->Concrete.FixedDim.itemsize;
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
memcpy(cp, ptr, t->datasize); cp += t->datasize;
|
2218
|
+
memcpy(cp, s, tlen); cp += tlen;
|
2219
|
+
memcpy(cp, &t->datasize, 8);
|
2220
|
+
ndt_free(s);
|
2221
|
+
|
2222
|
+
return result;
|
2223
|
+
}
|
2224
|
+
|
2225
|
+
|
1810
2226
|
/*************************** Singleton methods ********************************/
|
1811
2227
|
|
2228
|
+
|
2229
|
+
/* Implement XND.deserialize */
|
1812
2230
|
static VALUE
|
1813
|
-
|
2231
|
+
XND_s_deserialize(VALUE klass, VALUE v)
|
1814
2232
|
{
|
2233
|
+
NDT_STATIC_CONTEXT(ctx);
|
2234
|
+
VALUE mblock, self;
|
2235
|
+
bool overflow = false;
|
2236
|
+
int64_t mblock_size;
|
2237
|
+
MemoryBlockObject *mblock_p;
|
1815
2238
|
XndObject *self_p;
|
1816
|
-
|
2239
|
+
|
2240
|
+
Check_Type(v, T_STRING);
|
2241
|
+
|
2242
|
+
const int64_t size = RSTRING_LEN(v);
|
2243
|
+
if (size < 8) {
|
2244
|
+
goto invalid_format;
|
2245
|
+
}
|
2246
|
+
|
2247
|
+
const char *s = RSTRING_PTR(v);
|
2248
|
+
memcpy(&mblock_size, s+size-8, 8);
|
2249
|
+
if (mblock_size < 0) {
|
2250
|
+
goto invalid_format;
|
2251
|
+
}
|
2252
|
+
|
2253
|
+
const int64_t tmp = ADDi64(mblock_size, 8, &overflow);
|
2254
|
+
const int64_t tlen = size - tmp;
|
2255
|
+
if (overflow || tlen < 0) {
|
2256
|
+
goto invalid_format;
|
2257
|
+
}
|
2258
|
+
|
2259
|
+
const ndt_t *t = ndt_deserialize(s+mblock_size, tlen, &ctx);
|
2260
|
+
if (t == NULL) {
|
2261
|
+
seterr(&ctx);
|
2262
|
+
}
|
2263
|
+
|
2264
|
+
if (t->datasize != mblock_size) {
|
2265
|
+
goto invalid_format;
|
2266
|
+
}
|
2267
|
+
|
2268
|
+
VALUE type = rb_ndtypes_from_type(t);
|
2269
|
+
ndt_decref(t);
|
2270
|
+
|
2271
|
+
mblock = mblock_empty(type, XND_OWN_EMBEDDED);
|
2272
|
+
GET_MBLOCK(mblock, mblock_p);
|
2273
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
2274
|
+
|
2275
|
+
memcpy(mblock_p->xnd->master.ptr, s, mblock_size);
|
1817
2276
|
|
1818
2277
|
self = XndObject_alloc();
|
1819
2278
|
GET_XND(self, self_p);
|
2279
|
+
XND_from_mblock(self_p, mblock);
|
2280
|
+
|
2281
|
+
rb_xnd_gc_guard_register_xnd_mblock(self_p, mblock);
|
2282
|
+
rb_xnd_gc_guard_register_xnd_type(self_p, type);
|
2283
|
+
|
2284
|
+
return self;
|
1820
2285
|
|
1821
|
-
|
1822
|
-
|
2286
|
+
invalid_format:
|
2287
|
+
rb_raise(rb_eValueError, "invalid format for xnd deserialization.");
|
2288
|
+
}
|
2289
|
+
|
2290
|
+
static VALUE
|
2291
|
+
RubyXND_s_empty(VALUE klass, VALUE origin_type, VALUE device)
|
2292
|
+
{
|
2293
|
+
XndObject *self_p;
|
2294
|
+
MemoryBlockObject *mblock_p;
|
2295
|
+
VALUE self, mblock;
|
2296
|
+
VALUE type;
|
2297
|
+
VALUE mblock_type, xnd_type;
|
2298
|
+
uint32_t flags = 0;
|
2299
|
+
|
2300
|
+
self = XndObject_alloc();
|
2301
|
+
GET_XND(self, self_p);
|
1823
2302
|
|
2303
|
+
if (device != Qnil) {
|
2304
|
+
flags = device_flags(device);
|
2305
|
+
}
|
2306
|
+
|
2307
|
+
type = rb_ndtypes_from_object(origin_type);
|
2308
|
+
mblock = mblock_empty(type, flags);
|
2309
|
+
|
1824
2310
|
XND_from_mblock(self_p, mblock);
|
1825
|
-
|
2311
|
+
GET_MBLOCK(mblock, mblock_p);
|
2312
|
+
|
2313
|
+
rb_xnd_gc_guard_register_xnd_mblock(self_p, mblock);
|
2314
|
+
rb_xnd_gc_guard_register_xnd_type(self_p, type);
|
2315
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
1826
2316
|
|
1827
2317
|
return self;
|
1828
2318
|
}
|
@@ -1842,9 +2332,7 @@ rb_xnd_hash_size(VALUE hash)
|
|
1842
2332
|
*/
|
1843
2333
|
int
|
1844
2334
|
rb_xnd_get_complex_values(VALUE comp, double *real, double *imag)
|
1845
|
-
{
|
1846
|
-
Check_Type(comp, T_COMPLEX);
|
1847
|
-
|
2335
|
+
{
|
1848
2336
|
*real = NUM2DBL(rb_funcall(comp, rb_intern("real"), 0, NULL));
|
1849
2337
|
*imag = NUM2DBL(rb_funcall(comp, rb_intern("imag"), 0, NULL));
|
1850
2338
|
|
@@ -1873,36 +2361,45 @@ rb_xnd_const_xnd(VALUE xnd)
|
|
1873
2361
|
VALUE
|
1874
2362
|
rb_xnd_from_xnd(xnd_t *x)
|
1875
2363
|
{
|
1876
|
-
VALUE mblock, xnd;
|
2364
|
+
VALUE mblock, xnd, type;
|
1877
2365
|
XndObject *xnd_p;
|
2366
|
+
MemoryBlockObject *mblock_p;
|
1878
2367
|
|
1879
2368
|
mblock = mblock_from_xnd(x);
|
1880
2369
|
xnd = XndObject_alloc();
|
1881
2370
|
GET_XND(xnd, xnd_p);
|
2371
|
+
GET_MBLOCK(mblock, mblock_p);
|
2372
|
+
type = mblock_p->type;
|
1882
2373
|
|
1883
2374
|
XND_from_mblock(xnd_p, mblock);
|
1884
|
-
|
2375
|
+
|
2376
|
+
rb_xnd_gc_guard_register_xnd_mblock(xnd_p, mblock);
|
2377
|
+
rb_xnd_gc_guard_register_xnd_type(xnd_p, type);
|
2378
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
1885
2379
|
|
1886
2380
|
return xnd;
|
1887
2381
|
}
|
1888
2382
|
|
1889
2383
|
/* Create an XND object of type ndt_t */
|
1890
2384
|
VALUE
|
1891
|
-
rb_xnd_empty_from_type(ndt_t *t)
|
2385
|
+
rb_xnd_empty_from_type(const ndt_t *t, uint32_t flags)
|
1892
2386
|
{
|
1893
2387
|
MemoryBlockObject *mblock_p;
|
1894
2388
|
XndObject *xnd_p;
|
1895
2389
|
VALUE type, mblock, xnd;
|
1896
2390
|
|
1897
2391
|
type = rb_ndtypes_from_type(t);
|
1898
|
-
mblock = mblock_empty(type);
|
2392
|
+
mblock = mblock_empty(type, flags);
|
1899
2393
|
xnd = XndObject_alloc();
|
1900
2394
|
|
1901
2395
|
GET_XND(xnd, xnd_p);
|
1902
|
-
rb_xnd_gc_guard_register(xnd_p, mblock);
|
1903
2396
|
|
1904
2397
|
XND_from_mblock(xnd_p, mblock);
|
1905
2398
|
|
2399
|
+
rb_xnd_gc_guard_register_xnd_mblock(xnd_p, mblock);
|
2400
|
+
rb_xnd_gc_guard_register_xnd_type(xnd_p, type);
|
2401
|
+
rb_xnd_gc_guard_register_mblock_type(mblock_p, type);
|
2402
|
+
|
1906
2403
|
return xnd;
|
1907
2404
|
}
|
1908
2405
|
|
@@ -1955,16 +2452,31 @@ void Init_ruby_xnd(void)
|
|
1955
2452
|
|
1956
2453
|
/* initializers */
|
1957
2454
|
rb_define_alloc_func(cRubyXND, RubyXND_allocate);
|
1958
|
-
rb_define_method(cRubyXND, "initialize", RubyXND_initialize,
|
2455
|
+
rb_define_method(cRubyXND, "initialize", RubyXND_initialize, 3);
|
2456
|
+
|
2457
|
+
/* singleton methods */
|
2458
|
+
rb_define_singleton_method(cRubyXND, "empty", RubyXND_s_empty, 2);
|
2459
|
+
rb_define_singleton_method(cXND, "deserialize", XND_s_deserialize, 1);
|
1959
2460
|
|
1960
2461
|
/* instance methods */
|
1961
2462
|
rb_define_method(cXND, "type", XND_type, 0);
|
2463
|
+
rb_define_method(cXND, "dtype", XND_dtype, 0);
|
1962
2464
|
rb_define_method(cXND, "value", XND_value, 0);
|
1963
2465
|
rb_define_method(cXND, "[]", XND_array_aref, -1);
|
1964
2466
|
rb_define_method(cXND, "[]=", XND_array_store, -1);
|
1965
2467
|
rb_define_method(cXND, "==", XND_eqeq, 1);
|
2468
|
+
rb_define_method(cXND, "serialize", XND_serialize, 0);
|
2469
|
+
rb_define_method(cXND, "copy_contiguous", XND_copy_contiguous, -1);
|
2470
|
+
rb_define_method(cXND, "_transpose", XND_transpose, 1);
|
2471
|
+
rb_define_method(cXND, "_reshape", XND_reshape, 2);
|
2472
|
+
|
1966
2473
|
// rb_define_method(cXND, "!=", XND_neq, 1);
|
1967
2474
|
rb_define_method(cXND, "<=>", XND_spaceship, 1);
|
2475
|
+
rb_define_method(cXND, "<", XND_lt, 1);
|
2476
|
+
rb_define_method(cXND, "<=", XND_lteq, 1);
|
2477
|
+
rb_define_method(cXND, ">", XND_gt, 1);
|
2478
|
+
rb_define_method(cXND, ">=", XND_gteq, 1);
|
2479
|
+
rb_define_method(cXND, "<=>", XND_spaceship, 1);
|
1968
2480
|
rb_define_method(cXND, "strict_equal", XND_strict_equal, 1);
|
1969
2481
|
rb_define_method(cXND, "size", XND_size, 0);
|
1970
2482
|
rb_define_method(cXND, "short_value", XND_short_value, 1);
|
@@ -1972,9 +2484,6 @@ void Init_ruby_xnd(void)
|
|
1972
2484
|
/* iterators */
|
1973
2485
|
rb_define_method(cXND, "each", XND_each, 0);
|
1974
2486
|
|
1975
|
-
/* singleton methods */
|
1976
|
-
rb_define_singleton_method(cXND, "empty", XND_s_empty, 1);
|
1977
|
-
|
1978
2487
|
/* GC guard */
|
1979
2488
|
rb_xnd_init_gc_guard();
|
1980
2489
|
|