alexgutteridge-rsruby 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/ext/Converters.c ADDED
@@ -0,0 +1,667 @@
1
+ /*
2
+ * == Author
3
+ * Alex Gutteridge
4
+ *
5
+ * == Copyright
6
+ *Copyright (C) 2006 Alex Gutteridge
7
+ *
8
+ * The Original Code is the RPy python module.
9
+ *
10
+ * The Initial Developer of the Original Code is Walter Moreira.
11
+ * Portions created by the Initial Developer are Copyright (C) 2002
12
+ * the Initial Developer. All Rights Reserved.
13
+ *
14
+ * Contributor(s):
15
+ * Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
16
+ *
17
+ *This library is free software; you can redistribute it and/or
18
+ *modify it under the terms of the GNU Lesser General Public
19
+ *License as published by the Free Software Foundation; either
20
+ *version 2.1 of the License, or (at your option) any later version.
21
+ *
22
+ *This library is distributed in the hope that it will be useful,
23
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25
+ *Lesser General Public License for more details.
26
+ *
27
+ *You should have received a copy of the GNU Lesser General Public
28
+ *License along with this library; if not, write to the Free Software
29
+ *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30
+ */
31
+
32
+ #include <rsruby.h>
33
+ #include "Converters.h"
34
+
35
+ // ************** Converters from Ruby to R *********//
36
+
37
+
38
+ SEXP ruby_to_R(VALUE obj)
39
+ {
40
+ SEXP robj;
41
+ VALUE str;
42
+ char buf [100];
43
+
44
+ //Return nil if object is nil
45
+ if (obj == Qnil) {
46
+ return R_NilValue;
47
+ }
48
+
49
+ //If object has 'as_r' then call it and use
50
+ //returned value subsequently
51
+ if (rb_respond_to(obj, rb_intern("as_r"))){
52
+ obj = rb_funcall(obj,rb_intern("as_r"),0);
53
+ if (!obj)
54
+ return NULL;
55
+ }
56
+
57
+ if (Robj_Check(obj))
58
+ {
59
+ Data_Get_Struct(obj, struct SEXPREC, robj);
60
+ PROTECT(robj);
61
+ }
62
+ else if (obj == Qtrue || obj == Qfalse)
63
+ {
64
+ PROTECT(robj = NEW_LOGICAL(1));
65
+ if (obj == Qtrue){
66
+ LOGICAL_DATA(robj)[0] = TRUE;
67
+ } else {
68
+ LOGICAL_DATA(robj)[0] = FALSE;
69
+ }
70
+
71
+ }
72
+ else if (TYPE(obj) == T_FIXNUM ||
73
+ TYPE(obj) == T_BIGNUM)
74
+ {
75
+ PROTECT(robj = NEW_INTEGER(1));
76
+ INTEGER_DATA(robj)[0] = NUM2LONG(obj);
77
+ }
78
+ else if (TYPE(obj) == T_FLOAT)
79
+ {
80
+ PROTECT(robj = NEW_NUMERIC(1));
81
+ NUMERIC_DATA(robj)[0] = NUM2DBL(obj);
82
+ }
83
+ else if (RubyComplex_Check(obj))
84
+ {
85
+ PROTECT(robj = NEW_COMPLEX(1));
86
+ COMPLEX_DATA(robj)[0].r = NUM2DBL(rb_funcall(obj,rb_intern("real"),0));
87
+ COMPLEX_DATA(robj)[0].i = NUM2DBL(rb_funcall(obj,rb_intern("image"),0));
88
+ }
89
+ else if (!NIL_P(rb_check_string_type(obj)))
90
+ {
91
+ PROTECT(robj = NEW_STRING(1));
92
+ SET_STRING_ELT(robj, 0, COPY_TO_USER_STRING(RSTRING(obj)->ptr));
93
+ }
94
+ else if (!NIL_P(rb_check_array_type(obj)))
95
+ {
96
+ PROTECT(robj = array_to_R(obj));
97
+ }
98
+ else if (TYPE(obj) == T_HASH)
99
+ {
100
+ PROTECT(robj = hash_to_R(obj));
101
+ }
102
+ else
103
+ {
104
+ str = rb_funcall(obj,rb_intern("inspect"),0);
105
+ str = rb_funcall(str,rb_intern("slice"),2,INT2NUM(0),INT2NUM(60));
106
+ sprintf(buf,"Unsupported object '%s' passed to R.\n",RSTRING(str)->ptr);
107
+ rb_raise(rb_eArgError,buf);
108
+ PROTECT(robj = NULL); /* Protected to avoid stack inbalance */
109
+ }
110
+
111
+ UNPROTECT(1);
112
+ return robj;
113
+ }
114
+
115
+ /* Make a R list or vector from a Ruby array */
116
+ SEXP array_to_R(VALUE obj)
117
+ {
118
+ VALUE it;
119
+ SEXP robj, rit;
120
+ int i, state;
121
+
122
+ /* This matrix defines what mode a vector should take given what
123
+ it already contains and a new item
124
+
125
+ E.g. Row 0 indicates that if we've seen an any, the vector will
126
+ always remain an any. Row 3 indicates that if we've seen a
127
+ float, then seeing an boolean, integer, or float will preserve
128
+ the vector as a float vector, while seeing a string or an Robj will
129
+ convert it into an any vector.
130
+ */
131
+ int fsm[7][7] = {
132
+ {0, 0, 0, 0, 0, 0, 0}, // any
133
+ {0, 1, 2, 3, 4, 0, 0}, // bool
134
+ {0, 2, 2, 3, 4, 0, 0}, // int
135
+ {0, 3, 3, 3, 4, 0, 0}, // float
136
+ {0, 4, 4, 4, 4, 0, 0}, // complex
137
+ {0, 0, 0, 0, 0, 5, 0}, // string
138
+ {0, 0, 0, 0, 0, 0, 6} // RObj
139
+ };
140
+
141
+ //Probably unnessecary but just in case
142
+ obj = rb_check_array_type(obj);
143
+
144
+ if (RARRAY(obj)->len == 0)
145
+ return R_NilValue;
146
+
147
+ PROTECT(robj = NEW_LIST(RARRAY(obj)->len));
148
+
149
+ state = -1;
150
+ for (i=0; i<RARRAY(obj)->len; i++) {
151
+
152
+ it = rb_ary_entry(obj, i);
153
+
154
+ if (state < 0)
155
+ state = type_to_int(it);
156
+ else
157
+ state = fsm[state][type_to_int(it)];
158
+
159
+ if (!(rit = ruby_to_R(it)))
160
+ goto exception;
161
+
162
+ SET_VECTOR_ELT(robj, i, rit);
163
+ }
164
+
165
+ switch(state)
166
+ {
167
+ case INT_T:
168
+ robj = AS_INTEGER(robj);
169
+ break;
170
+ case BOOL_T:
171
+ robj = AS_LOGICAL(robj);
172
+ break;
173
+ case FLOAT_T:
174
+ robj = AS_NUMERIC(robj);
175
+ break;
176
+ case COMPLEX_T:
177
+ robj = AS_COMPLEX(robj);
178
+ break;
179
+ case STRING_T:
180
+ robj = AS_CHARACTER(robj);
181
+ break;
182
+ default:;
183
+ /* Otherwise, it's either an ANY_T or ROBJ_T - we want ANY */
184
+ }
185
+
186
+ UNPROTECT(1);
187
+ return robj;
188
+
189
+ exception:
190
+ UNPROTECT(1);
191
+ rb_raise(rb_eArgError,"Error converting Array to R\n");
192
+ return NULL;
193
+ }
194
+
195
+ /* Make a R named list or vector from a Ruby Hash */
196
+ SEXP
197
+ hash_to_R(VALUE obj)
198
+ {
199
+ VALUE keys, values;
200
+ SEXP robj, names;
201
+
202
+ //TODO - Baffling. Not sure what's wrong with these functions?
203
+ //rb_hash_keys(proc_table);
204
+ //rb_hash_values(proc_table);
205
+ //rb_hash_size(proc_table);
206
+ //compiles, but complains they are undefined symbols when run...
207
+
208
+ if (FIX2INT(rb_funcall(obj,rb_intern("size"),0)) == 0)
209
+ return R_NilValue;
210
+
211
+ /* If 'keys' succeed and 'values' fails this leaks */
212
+ if (!(keys = rb_funcall(obj,rb_intern("keys"),0)))
213
+ return NULL;
214
+ if (!(values = rb_funcall(obj,rb_intern("values"),0)))
215
+ return NULL;
216
+
217
+ if (!(robj = array_to_R(values)))
218
+ goto fail;
219
+ if (!(names = array_to_R(keys)))
220
+ goto fail;
221
+
222
+ PROTECT(robj);
223
+ SET_NAMES(robj, names);
224
+ UNPROTECT(1);
225
+
226
+ return robj;
227
+
228
+ fail:
229
+ return NULL;
230
+ }
231
+
232
+ int
233
+ type_to_int(VALUE obj)
234
+ {
235
+ if (obj == Qtrue || obj == Qfalse)
236
+ return BOOL_T;
237
+ else if (TYPE(obj) == T_FIXNUM ||
238
+ TYPE(obj) == T_BIGNUM)
239
+ return INT_T;
240
+ else if (TYPE(obj) == T_FLOAT)
241
+ return FLOAT_T;
242
+ else if (RubyComplex_Check(obj))
243
+ return COMPLEX_T;
244
+ //NB (TODO): This line means that objects are coerced into
245
+ //String form if possible rather than leaving them as RObj
246
+ else if (!NIL_P(rb_check_string_type(obj)))
247
+ return STRING_T;
248
+ else if (Robj_Check(obj))
249
+ return ROBJ_T;
250
+ else
251
+ return ANY_T;
252
+ }
253
+
254
+ // ************** Converters from R to Ruby *********//
255
+
256
+ VALUE to_ruby_with_mode(SEXP robj, int mode)
257
+ {
258
+ VALUE obj;
259
+ int i;
260
+
261
+ switch (mode)
262
+ {
263
+ case PROC_CONVERSION:
264
+ i = to_ruby_proc(robj, &obj);
265
+ if (i<0) return Qnil;
266
+ if (i==1) break;
267
+ case CLASS_CONVERSION:
268
+ i = to_ruby_class(robj, &obj);
269
+ if (i<0) return Qnil;
270
+ if (i==1) break;
271
+ case BASIC_CONVERSION:
272
+ i = to_ruby_basic(robj, &obj);
273
+ if (i<0) return Qnil;
274
+ if (i==1) break;
275
+ case VECTOR_CONVERSION:
276
+ i = to_ruby_vector(robj, &obj, mode=VECTOR_CONVERSION);
277
+ if (i<0) return Qnil;
278
+ if (i==1) break;
279
+ default:
280
+ obj = Data_Wrap_Struct(rb_const_get(rb_cObject,
281
+ rb_intern("RObj")), 0, 0, robj);
282
+ rb_iv_set(obj,"@conversion",INT2FIX(TOP_MODE));
283
+ rb_iv_set(obj,"@wrap",Qfalse);
284
+ }
285
+
286
+ return obj;
287
+ }
288
+
289
+ /* Convert an R object to a 'basic' Ruby object (mode 2) */
290
+ /* NOTE: R vectors of length 1 will yield a Ruby scalar */
291
+ int
292
+ to_ruby_basic(SEXP robj, VALUE *obj)
293
+ {
294
+ int status;
295
+ VALUE tmp;
296
+
297
+ status = to_ruby_vector(robj, &tmp, BASIC_CONVERSION);
298
+
299
+ if(status==1 && TYPE(tmp) == T_ARRAY && RARRAY(tmp)->len == 1)
300
+ {
301
+ *obj = rb_ary_entry(tmp, 0);
302
+ }
303
+ else
304
+ *obj = tmp;
305
+
306
+ return status;
307
+ }
308
+
309
+
310
+ /* Convert an R object to a 'vector' Ruby object (mode 1) */
311
+ /* NOTE: R vectors of length 1 will yield a Ruby array of length 1*/
312
+ int
313
+ to_ruby_vector(SEXP robj, VALUE *obj, int mode)
314
+ {
315
+ VALUE it, tmp;
316
+ VALUE params[2];
317
+ SEXP names, dim;
318
+ int len, *integers, i, type;
319
+ char *strings, *thislevel;
320
+ double *reals;
321
+ Rcomplex *complexes;
322
+
323
+ if (!robj)
324
+ return -1; /* error */
325
+
326
+ if (robj == R_NilValue) {
327
+ *obj = Qnil;
328
+ return 1; /* succeed */
329
+ }
330
+
331
+ len = GET_LENGTH(robj);
332
+ tmp = rb_ary_new2(len);
333
+ type = TYPEOF(robj);
334
+
335
+ for (i=0; i<len; i++) {
336
+ switch (type)
337
+ {
338
+ case LGLSXP:
339
+ integers = INTEGER(robj);
340
+ if(integers[i]==NA_INTEGER) /* watch out for NA's */
341
+ {
342
+ if (!(it = INT2NUM(integers[i])))
343
+ return -1;
344
+ }
345
+ //TODO - not sure of the conversion here.
346
+ else if (integers[i] != 0){
347
+ it = Qtrue;
348
+ } else if (integers[i] == 0){
349
+ it = Qfalse;
350
+ } else {
351
+ return -1;
352
+ }
353
+ break;
354
+ case INTSXP:
355
+ integers = INTEGER(robj);
356
+ if(isFactor(robj)) {
357
+ /* Watch for NA's! */
358
+ if(integers[i]==NA_INTEGER)
359
+ it = rb_str_new2(CHAR(NA_STRING));
360
+ else
361
+ {
362
+ thislevel = CHAR(STRING_ELT(GET_LEVELS(robj), integers[i]-1));
363
+ if (!(it = rb_str_new2(thislevel)))
364
+ return -1;
365
+ }
366
+ }
367
+ else {
368
+ if (!(it = LONG2NUM(integers[i])))
369
+ return -1;
370
+ }
371
+ break;
372
+ case REALSXP:
373
+ reals = REAL(robj);
374
+ if (!(it = rb_float_new(reals[i])))
375
+ return -1;
376
+ break;
377
+ case CPLXSXP:
378
+ complexes = COMPLEX(robj);
379
+
380
+ params[0] = rb_float_new(complexes[i].r);
381
+ params[1] = rb_float_new(complexes[i].i);
382
+
383
+ if (!(it = rb_class_new_instance(2, params, rb_const_get(rb_cObject, rb_intern("Complex")))))
384
+
385
+ return -1;
386
+ break;
387
+ case STRSXP:
388
+ if(STRING_ELT(robj, i)==R_NaString)
389
+ it = rb_str_new2(CHAR(NA_STRING));
390
+ else
391
+ {
392
+ strings = CHAR(STRING_ELT(robj, i));
393
+ if (!(it = rb_str_new2(strings)))
394
+ return -1;
395
+ }
396
+ break;
397
+ case LISTSXP:
398
+ if (!(it = to_ruby_with_mode(elt(robj, i), mode)))
399
+ return -1;
400
+ break;
401
+ case VECSXP:
402
+ if (!(it = to_ruby_with_mode(VECTOR_ELT(robj, i), mode)))
403
+ return -1;
404
+ break;
405
+ default:
406
+ return 0; /* failed */
407
+ }
408
+ rb_ary_store(tmp, i, it);
409
+ }
410
+
411
+ dim = GET_DIM(robj);
412
+ if (dim != R_NilValue) {
413
+ len = GET_LENGTH(dim);
414
+ *obj = to_ruby_array(tmp, INTEGER(dim), len);
415
+ return 1;
416
+ }
417
+
418
+ names = GET_NAMES(robj);
419
+ if (names == R_NilValue)
420
+ *obj = tmp;
421
+ else {
422
+ *obj = to_ruby_hash(tmp, names);
423
+ }
424
+
425
+ return 1;
426
+ }
427
+
428
+ /* Search a conversion procedure from the proc table */
429
+ int
430
+ from_proc_table(SEXP robj, VALUE *fun)
431
+ {
432
+ VALUE proc_table, procs, proc, funs, res, obj, mode;
433
+ VALUE args[2];
434
+ int i, l, error;
435
+
436
+ proc_table = rb_iv_get(RSRUBY,"@proc_table");
437
+
438
+ proc = Qnil;
439
+
440
+ //TODO - Baffling. Not sure what's wrong with these functions?
441
+ //procs = rb_hash_keys(proc_table);
442
+ //funs = rb_hash_values(proc_table);
443
+ //l = FIX2INT(rb_hash_size(proc_table));
444
+
445
+ procs = rb_funcall(proc_table,rb_intern("keys"),0);
446
+ funs = rb_funcall(proc_table,rb_intern("values"),0);
447
+ l = FIX2INT(rb_funcall(proc_table,rb_intern("size"),0));
448
+
449
+ obj = Data_Wrap_Struct(rb_const_get(rb_cObject,
450
+ rb_intern("RObj")), 0, 0, robj);
451
+ rb_iv_set(obj,"@conversion",INT2FIX(TOP_MODE));
452
+ rb_iv_set(obj,"@wrap",Qfalse);
453
+
454
+ error = 0;
455
+ for (i=0; i<l; i++) {
456
+ proc = rb_ary_entry(procs, i);
457
+
458
+ mode = rb_iv_get(RSRUBY,"@default_mode");
459
+ rb_iv_set(RSRUBY,
460
+ "@default_mode",
461
+ INT2FIX(BASIC_CONVERSION));
462
+
463
+ //New safe code
464
+ args[0] = proc;
465
+ args[1] = obj;
466
+ res = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
467
+
468
+ if (RTEST(res)) {
469
+ *fun = rb_ary_entry(funs, i);
470
+ break;
471
+ }
472
+ }
473
+
474
+ return error;
475
+ }
476
+
477
+ VALUE call_proc(VALUE data){
478
+ VALUE *args = (VALUE *) data;
479
+ return rb_funcall(args[0], rb_intern("call"), 1, args[1]);
480
+ }
481
+
482
+ VALUE reset_mode(VALUE mode){
483
+
484
+ rb_iv_set(RSRUBY,
485
+ "@default_mode",
486
+ mode);
487
+
488
+ return Qnil;
489
+
490
+ }
491
+
492
+ int
493
+ to_ruby_proc(SEXP robj, VALUE *obj)
494
+ {
495
+ VALUE fun=Qnil, tmp, mode;
496
+ VALUE args[2];
497
+ int i;
498
+
499
+ //Find function from proc table. integer is returned
500
+ //to indicate success/failure
501
+
502
+ i = from_proc_table(robj, &fun);
503
+
504
+ if (i < 0)
505
+ return -1; /* an error occurred */
506
+
507
+ if (fun==Qnil)
508
+ return 0; /* conversion failed */
509
+
510
+ //Create new object based on robj and call the function
511
+ //found above with it as argument
512
+ tmp = Data_Wrap_Struct(rb_const_get(rb_cObject,
513
+ rb_intern("RObj")), 0, 0, robj);
514
+ rb_iv_set(tmp,"@conversion",INT2FIX(TOP_MODE));
515
+ rb_iv_set(tmp,"@wrap",Qfalse);
516
+
517
+ //Again set conversion mode to basic to prevent recursion
518
+ mode = rb_iv_get(RSRUBY,"@default_mode");
519
+ rb_iv_set(RSRUBY, "@default_mode", INT2FIX(BASIC_CONVERSION));
520
+
521
+ //New safe code
522
+ args[0] = fun;
523
+ args[1] = tmp;
524
+ *obj = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
525
+
526
+ return 1; /* conversion succeed */
527
+ }
528
+
529
+ /* Search a conversion procedure from the class attribute */
530
+ VALUE from_class_table(SEXP robj)
531
+ {
532
+ SEXP rclass;
533
+ VALUE key, fun, class_table;
534
+ int i;
535
+
536
+ class_table = rb_iv_get(RSRUBY, "@class_table");
537
+
538
+ PROTECT(rclass = GET_CLASS(robj));
539
+
540
+ fun = Qnil;
541
+ if (rclass != R_NilValue) {
542
+
543
+ //key may be an array or string depending on
544
+ //the class specification
545
+ key = to_ruby_with_mode(rclass, BASIC_CONVERSION);
546
+ fun = rb_hash_aref(class_table, key);
547
+
548
+ //If we haven't found a function then go through
549
+ //each class in rclass and look for a match
550
+ if (fun==Qnil) {
551
+
552
+ for (i=0; i<GET_LENGTH(rclass); i++){
553
+ fun = rb_hash_aref(class_table,
554
+ rb_str_new2(CHAR(STRING_ELT(rclass, i))));
555
+ if (fun != Qnil){
556
+ break;
557
+ }
558
+ }
559
+ }
560
+ }
561
+ UNPROTECT(1);
562
+ return fun;
563
+ }
564
+
565
+ /* Convert a Robj to a Ruby object via the class table (mode 3) */
566
+ /* See the docs for conversion rules */
567
+ int
568
+ to_ruby_class(SEXP robj, VALUE *obj)
569
+ {
570
+ VALUE fun, tmp, mode;
571
+ VALUE args[2];
572
+
573
+ fun = from_class_table(robj);
574
+
575
+ if (fun==Qnil)
576
+ return 0; /* conversion failed */
577
+
578
+ tmp = Data_Wrap_Struct(rb_const_get(rb_cObject,
579
+ rb_intern("RObj")), 0, 0, robj);
580
+ rb_iv_set(tmp,"@conversion",INT2FIX(TOP_MODE));
581
+ rb_iv_set(tmp,"@wrap",Qfalse);
582
+
583
+ //Again set conversion mode to basic to prevent recursion
584
+ mode = rb_iv_get(RSRUBY, "@default_mode");
585
+ rb_iv_set(RSRUBY, "@default_mode", INT2FIX(BASIC_CONVERSION));
586
+
587
+ //New safe code
588
+ args[0] = fun;
589
+ args[1] = tmp;
590
+ *obj = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
591
+ //*obj = rb_funcall(fun, rb_intern("call"), 1, tmp);
592
+
593
+ return 1; /* conversion succeed */
594
+ }
595
+
596
+ /* Convert a R named vector or list to a Ruby Hash */
597
+ VALUE to_ruby_hash(VALUE obj, SEXP names)
598
+ {
599
+ int len, i;
600
+ VALUE it, hash;
601
+ char *name;
602
+
603
+ if ((len = RARRAY(obj)->len) < 0)
604
+ return Qnil;
605
+
606
+ hash = rb_hash_new();
607
+ for (i=0; i<len; i++) {
608
+ it = rb_ary_entry(obj, i);
609
+ name = CHAR(STRING_ELT(names, i));
610
+ rb_hash_aset(hash, rb_str_new2(name), it);
611
+ }
612
+
613
+ return hash;
614
+ }
615
+
616
+ /* We need to transpose the list because R makes array by the
617
+ * fastest index */
618
+ VALUE ltranspose(VALUE list, int *dims, int *strides,
619
+ int pos, int shift, int len)
620
+ {
621
+ VALUE nl, it;
622
+ int i;
623
+
624
+ if (!(nl = rb_ary_new2(dims[pos])))
625
+ return Qnil;
626
+
627
+ if (pos == len-1) {
628
+ for (i=0; i<dims[pos]; i++) {
629
+ if (!(it = rb_ary_entry(list, i*strides[pos]+shift)))
630
+ return Qnil;
631
+ rb_ary_store(nl, i, it);
632
+ }
633
+ return nl;
634
+ }
635
+
636
+ for (i=0; i<dims[pos]; i++) {
637
+ if (!(it = ltranspose(list, dims, strides, pos+1, shift, len)))
638
+ return Qnil;
639
+ rb_ary_store(nl, i, it);
640
+ shift += strides[pos];
641
+ }
642
+
643
+ return nl;
644
+ }
645
+
646
+ /* Convert a R Array to a Ruby Array (in the form of
647
+ * array of arrays of ...) */
648
+ VALUE to_ruby_array(VALUE obj, int *dims, int l)
649
+ {
650
+ VALUE list;
651
+ int i, c, *strides;
652
+
653
+ strides = (int *)ALLOC_N(int,l);
654
+ if (!strides)
655
+ rb_raise(rb_eRuntimeError,"Could not allocate memory for array\n");
656
+
657
+ c = 1;
658
+ for (i=0; i<l; i++) {
659
+ strides[i] = c;
660
+ c *= dims[i];
661
+ }
662
+
663
+ list = ltranspose(obj, dims, strides, 0, 0, l);
664
+ free(strides);
665
+
666
+ return list;
667
+ }