nmatrix 0.0.9 → 0.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/History.txt +95 -1
  4. data/LICENSE.txt +2 -2
  5. data/README.rdoc +24 -26
  6. data/Rakefile +32 -16
  7. data/ext/nmatrix/data/complex.h +2 -2
  8. data/ext/nmatrix/data/data.cpp +27 -51
  9. data/ext/nmatrix/data/data.h +92 -4
  10. data/ext/nmatrix/data/meta.h +2 -2
  11. data/ext/nmatrix/data/rational.h +2 -2
  12. data/ext/nmatrix/data/ruby_object.h +2 -2
  13. data/ext/nmatrix/extconf.rb +87 -86
  14. data/ext/nmatrix/math.cpp +45 -40
  15. data/ext/nmatrix/math/asum.h +3 -3
  16. data/ext/nmatrix/math/geev.h +2 -2
  17. data/ext/nmatrix/math/gemm.h +6 -2
  18. data/ext/nmatrix/math/gemv.h +6 -2
  19. data/ext/nmatrix/math/ger.h +2 -2
  20. data/ext/nmatrix/math/gesdd.h +2 -2
  21. data/ext/nmatrix/math/gesvd.h +2 -2
  22. data/ext/nmatrix/math/getf2.h +2 -2
  23. data/ext/nmatrix/math/getrf.h +2 -2
  24. data/ext/nmatrix/math/getri.h +2 -2
  25. data/ext/nmatrix/math/getrs.h +7 -3
  26. data/ext/nmatrix/math/idamax.h +2 -2
  27. data/ext/nmatrix/math/inc.h +12 -6
  28. data/ext/nmatrix/math/laswp.h +2 -2
  29. data/ext/nmatrix/math/long_dtype.h +2 -2
  30. data/ext/nmatrix/math/math.h +16 -10
  31. data/ext/nmatrix/math/nrm2.h +3 -3
  32. data/ext/nmatrix/math/potrs.h +7 -3
  33. data/ext/nmatrix/math/rot.h +2 -2
  34. data/ext/nmatrix/math/rotg.h +2 -2
  35. data/ext/nmatrix/math/scal.h +2 -2
  36. data/ext/nmatrix/math/swap.h +2 -2
  37. data/ext/nmatrix/math/trsm.h +7 -3
  38. data/ext/nmatrix/nm_memory.h +60 -0
  39. data/ext/nmatrix/nmatrix.cpp +13 -47
  40. data/ext/nmatrix/nmatrix.h +37 -12
  41. data/ext/nmatrix/ruby_constants.cpp +4 -2
  42. data/ext/nmatrix/ruby_constants.h +4 -2
  43. data/ext/nmatrix/ruby_nmatrix.c +937 -170
  44. data/ext/nmatrix/storage/common.cpp +2 -2
  45. data/ext/nmatrix/storage/common.h +2 -2
  46. data/ext/nmatrix/storage/{dense.cpp → dense/dense.cpp} +253 -100
  47. data/ext/nmatrix/storage/{dense.h → dense/dense.h} +6 -5
  48. data/ext/nmatrix/storage/{list.cpp → list/list.cpp} +517 -98
  49. data/ext/nmatrix/storage/{list.h → list/list.h} +13 -6
  50. data/ext/nmatrix/storage/storage.cpp +48 -19
  51. data/ext/nmatrix/storage/storage.h +4 -4
  52. data/ext/nmatrix/storage/yale/class.h +112 -43
  53. data/ext/nmatrix/storage/yale/iterators/base.h +2 -2
  54. data/ext/nmatrix/storage/yale/iterators/iterator.h +2 -2
  55. data/ext/nmatrix/storage/yale/iterators/row.h +2 -2
  56. data/ext/nmatrix/storage/yale/iterators/row_stored.h +2 -2
  57. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +4 -3
  58. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +2 -2
  59. data/ext/nmatrix/storage/yale/math/transpose.h +2 -2
  60. data/ext/nmatrix/storage/yale/yale.cpp +343 -52
  61. data/ext/nmatrix/storage/yale/yale.h +7 -3
  62. data/ext/nmatrix/types.h +2 -2
  63. data/ext/nmatrix/util/io.cpp +5 -5
  64. data/ext/nmatrix/util/io.h +2 -2
  65. data/ext/nmatrix/util/sl_list.cpp +40 -27
  66. data/ext/nmatrix/util/sl_list.h +3 -3
  67. data/ext/nmatrix/util/util.h +2 -2
  68. data/lib/nmatrix.rb +2 -2
  69. data/lib/nmatrix/blas.rb +2 -2
  70. data/lib/nmatrix/enumerate.rb +17 -6
  71. data/lib/nmatrix/io/market.rb +2 -3
  72. data/lib/nmatrix/io/mat5_reader.rb +2 -2
  73. data/lib/nmatrix/io/mat_reader.rb +2 -2
  74. data/lib/nmatrix/lapack.rb +46 -46
  75. data/lib/nmatrix/math.rb +213 -20
  76. data/lib/nmatrix/monkeys.rb +24 -2
  77. data/lib/nmatrix/nmatrix.rb +394 -9
  78. data/lib/nmatrix/nvector.rb +2 -64
  79. data/lib/nmatrix/rspec.rb +2 -2
  80. data/lib/nmatrix/shortcuts.rb +14 -61
  81. data/lib/nmatrix/version.rb +11 -3
  82. data/lib/nmatrix/yale_functions.rb +4 -4
  83. data/nmatrix.gemspec +2 -7
  84. data/scripts/mac-brew-gcc.sh +11 -8
  85. data/scripts/mac-mavericks-brew-gcc.sh +22 -0
  86. data/spec/00_nmatrix_spec.rb +116 -7
  87. data/spec/01_enum_spec.rb +17 -3
  88. data/spec/02_slice_spec.rb +11 -3
  89. data/spec/blas_spec.rb +5 -2
  90. data/spec/elementwise_spec.rb +5 -2
  91. data/spec/io_spec.rb +27 -17
  92. data/spec/lapack_spec.rb +157 -9
  93. data/spec/math_spec.rb +95 -4
  94. data/spec/nmatrix_yale_spec.rb +21 -26
  95. data/spec/rspec_monkeys.rb +27 -0
  96. data/spec/rspec_spec.rb +2 -2
  97. data/spec/shortcuts_spec.rb +5 -10
  98. data/spec/slice_set_spec.rb +6 -2
  99. data/spec/spec_helper.rb +3 -2
  100. data/spec/stat_spec.rb +174 -158
  101. metadata +15 -15
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2013, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -43,7 +43,7 @@
43
43
 
44
44
  #include "data/data.h"
45
45
 
46
- #include "common.h"
46
+ #include "../common.h"
47
47
 
48
48
  #include "nmatrix.h"
49
49
 
@@ -73,8 +73,9 @@ DENSE_STORAGE* nm_dense_storage_create(nm::dtype_t dtype, size_t* shape, size_t
73
73
  void nm_dense_storage_delete(STORAGE* s);
74
74
  void nm_dense_storage_delete_ref(STORAGE* s);
75
75
  void nm_dense_storage_mark(STORAGE*);
76
- void nm_dense_storage_register_values(VALUE* values, size_t n);
77
- void nm_dense_storage_unregister_values(VALUE* values, size_t n);
76
+ void nm_dense_storage_register(const STORAGE* s);
77
+ void nm_dense_storage_unregister(const STORAGE* s);
78
+
78
79
 
79
80
  ///////////////
80
81
  // Accessors //
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2013, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -25,7 +25,6 @@
25
25
  //
26
26
  // List-of-lists n-dimensional matrix storage. Uses singly-linked
27
27
  // lists.
28
-
29
28
  /*
30
29
  * Standard Includes
31
30
  */
@@ -34,21 +33,22 @@
34
33
  #include <algorithm> // std::min
35
34
  #include <iostream>
36
35
  #include <vector>
36
+ #include <list>
37
37
 
38
38
  /*
39
39
  * Project Includes
40
40
  */
41
41
 
42
- #include "types.h"
42
+ #include "../../types.h"
43
43
 
44
- #include "data/data.h"
44
+ #include "../../data/data.h"
45
45
 
46
- #include "dense.h"
47
- #include "common.h"
46
+ #include "../dense/dense.h"
47
+ #include "../common.h"
48
48
  #include "list.h"
49
49
 
50
- #include "math/math.h"
51
- #include "util/sl_list.h"
50
+ #include "../../math/math.h"
51
+ #include "../../util/sl_list.h"
52
52
 
53
53
  /*
54
54
  * Macros
@@ -61,6 +61,8 @@
61
61
 
62
62
  extern "C" {
63
63
  static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coords, size_t* lengths, size_t n);
64
+ static void __nm_list_storage_unregister_temp_value_list(std::list<VALUE*>& temp_vals);
65
+ static void __nm_list_storage_unregister_temp_list_list(std::list<LIST*>& temp_vals, size_t recursions);
64
66
  }
65
67
 
66
68
  namespace nm { namespace list_storage {
@@ -78,11 +80,20 @@ public:
78
80
  offsets[i] += actual->offset[i];
79
81
  actual = reinterpret_cast<LIST_STORAGE*>(actual->src);
80
82
  }
83
+ nm_list_storage_register(actual);
84
+ nm_list_storage_register(ref);
81
85
  actual_shape_ = actual->shape;
82
86
 
83
87
  if (init_obj_ == Qnil) {
84
88
  init_obj_ = s->dtype == nm::RUBYOBJ ? *reinterpret_cast<VALUE*>(s->default_val) : rubyobj_from_cval(s->default_val, s->dtype).rval;
85
89
  }
90
+ nm_register_value(init_obj_);
91
+ }
92
+
93
+ ~RecurseData() {
94
+ nm_unregister_value(init_obj_);
95
+ nm_list_storage_unregister(ref);
96
+ nm_list_storage_unregister(actual);
86
97
  }
87
98
 
88
99
  dtype_t dtype() const { return ref->dtype; }
@@ -95,13 +106,13 @@ public:
95
106
  }
96
107
 
97
108
  size_t* copy_alloc_shape() const {
98
- size_t* new_shape = ALLOC_N(size_t, ref->dim);
109
+ size_t* new_shape = NM_ALLOC_N(size_t, ref->dim);
99
110
  memcpy(new_shape, shape_, sizeof(size_t)*ref->dim);
100
111
  return new_shape;
101
112
  }
102
113
 
103
114
  size_t actual_shape(size_t rec) const {
104
- return actual_shape_[ref->dim - rec - 1];
115
+ return actual_shape_[actual->dim - rec - 1];
105
116
  }
106
117
 
107
118
  size_t offset(size_t rec) const {
@@ -140,53 +151,157 @@ static bool eqeq_r(RecurseData& left, RecurseData& right, const LIST* l, const L
140
151
  template <typename SDType, typename TDType>
141
152
  static bool eqeq_empty_r(RecurseData& s, const LIST* l, size_t rec, const TDType* t_init);
142
153
 
143
-
144
154
  /*
145
155
  * Recursive helper for map_merged_stored_r which handles the case where one list is empty and the other is not.
146
156
  */
147
157
  static void map_empty_stored_r(RecurseData& result, RecurseData& s, LIST* x, const LIST* l, size_t rec, bool rev, const VALUE& t_init) {
158
+ if (s.dtype() == nm::RUBYOBJ) {
159
+ nm_list_storage_register_list(l, rec);
160
+ }
161
+ if (result.dtype() == nm::RUBYOBJ) {
162
+ nm_list_storage_register_list(x, rec);
163
+ }
164
+
148
165
  NODE *curr = l->first,
149
166
  *xcurr = NULL;
150
167
 
151
168
  // For reference matrices, make sure we start in the correct place.
152
- size_t offset = result.offset(rec);
153
- size_t x_shape = result.ref_shape(rec);
169
+ size_t offset = s.offset(rec);
170
+ size_t x_shape = s.ref_shape(rec);
154
171
 
155
172
  while (curr && curr->key < offset) { curr = curr->next; }
156
173
  if (curr && curr->key - offset >= x_shape) curr = NULL;
157
174
 
158
175
  if (rec) {
176
+ std::list<LIST*> temp_vals;
159
177
  while (curr) {
160
178
  LIST* val = nm::list::create();
161
179
  map_empty_stored_r(result, s, val, reinterpret_cast<const LIST*>(curr->val), rec-1, rev, t_init);
162
180
 
163
181
  if (!val->first) nm::list::del(val, 0);
164
- else nm::list::insert_helper(x, xcurr, curr->key - offset, val);
165
-
182
+ else {
183
+ nm_list_storage_register_list(val, rec-1);
184
+ temp_vals.push_front(val);
185
+ nm::list::insert_helper(x, xcurr, curr->key - offset, val);
186
+ }
166
187
  curr = curr->next;
167
188
  if (curr && curr->key - offset >= x_shape) curr = NULL;
168
189
  }
190
+ __nm_list_storage_unregister_temp_list_list(temp_vals, rec-1);
169
191
  } else {
192
+ std::list<VALUE*> temp_vals;
170
193
  while (curr) {
171
194
  VALUE val, s_val = rubyobj_from_cval(curr->val, s.dtype()).rval;
172
195
  if (rev) val = rb_yield_values(2, t_init, s_val);
173
196
  else val = rb_yield_values(2, s_val, t_init);
174
197
 
175
- if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue)
198
+ nm_register_value(val);
199
+
200
+ if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue) {
176
201
  xcurr = nm::list::insert_helper(x, xcurr, curr->key - offset, val);
202
+ temp_vals.push_front(reinterpret_cast<VALUE*>(xcurr->val));
203
+ nm_register_value(*reinterpret_cast<VALUE*>(xcurr->val));
204
+ }
205
+ nm_unregister_value(val);
177
206
 
178
207
  curr = curr->next;
179
208
  if (curr && curr->key - offset >= x_shape) curr = NULL;
180
209
  }
210
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
211
+ }
212
+
213
+ if (s.dtype() == nm::RUBYOBJ){
214
+ nm_list_storage_unregister_list(l, rec);
215
+ }
216
+ if (result.dtype() == nm::RUBYOBJ) {
217
+ nm_list_storage_unregister_list(x, rec);
181
218
  }
182
219
 
183
220
  }
184
221
 
185
222
 
223
+ /*
224
+ * Recursive helper function for nm_list_map_stored
225
+ */
226
+ static void map_stored_r(RecurseData& result, RecurseData& left, LIST* x, const LIST* l, size_t rec) {
227
+ if (left.dtype() == nm::RUBYOBJ) {
228
+ nm_list_storage_register_list(l, rec);
229
+ }
230
+ if (result.dtype() == nm::RUBYOBJ) {
231
+ nm_list_storage_register_list(x, rec);
232
+ }
233
+ NODE *lcurr = l->first,
234
+ *xcurr = x->first;
235
+
236
+ // For reference matrices, make sure we start in the correct place.
237
+ while (lcurr && lcurr->key < left.offset(rec)) { lcurr = lcurr->next; }
238
+
239
+ if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
240
+
241
+ if (rec) {
242
+ std::list<LIST*> temp_vals;
243
+ while (lcurr) {
244
+ size_t key;
245
+ LIST* val = nm::list::create();
246
+ map_stored_r(result, left, val, reinterpret_cast<const LIST*>(lcurr->val), rec-1);
247
+ key = lcurr->key - left.offset(rec);
248
+ lcurr = lcurr->next;
249
+
250
+ if (!val->first) nm::list::del(val, 0); // empty list -- don't insert
251
+ else {
252
+ nm_list_storage_register_list(val, rec-1);
253
+ temp_vals.push_front(val);
254
+ xcurr = nm::list::insert_helper(x, xcurr, key, val);
255
+ }
256
+ if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
257
+ }
258
+ __nm_list_storage_unregister_temp_list_list(temp_vals, rec-1);
259
+ } else {
260
+ std::list<VALUE*> temp_vals;
261
+ while (lcurr) {
262
+ size_t key;
263
+ VALUE val;
264
+
265
+ val = rb_yield_values(1, rubyobj_from_cval(lcurr->val, left.dtype()).rval);
266
+ key = lcurr->key - left.offset(rec);
267
+ lcurr = lcurr->next;
268
+
269
+ if (!rb_equal(val, result.init_obj())) {
270
+ xcurr = nm::list::insert_helper(x, xcurr, key, val);
271
+ temp_vals.push_front(reinterpret_cast<VALUE*>(xcurr->val));
272
+ nm_register_value(*reinterpret_cast<VALUE*>(xcurr->val));
273
+ }
274
+
275
+ if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
276
+ }
277
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
278
+ }
279
+
280
+ if (left.dtype() == nm::RUBYOBJ) {
281
+ nm_list_storage_unregister_list(l, rec);
282
+ }
283
+ if (result.dtype() == nm::RUBYOBJ) {
284
+ nm_list_storage_unregister_list(x, rec);
285
+ }
286
+ }
287
+
288
+
289
+
186
290
  /*
187
291
  * Recursive helper function for nm_list_map_merged_stored
188
292
  */
189
293
  static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseData& right, LIST* x, const LIST* l, const LIST* r, size_t rec) {
294
+ if (left.dtype() == nm::RUBYOBJ) {
295
+ nm_list_storage_register_list(l, rec);
296
+ }
297
+ if (right.dtype() == nm::RUBYOBJ) {
298
+ nm_list_storage_register_list(r, rec);
299
+ }
300
+ if (result.dtype() == nm::RUBYOBJ) {
301
+ nm_list_storage_register_list(x, rec);
302
+ }
303
+
304
+
190
305
  NODE *lcurr = l->first,
191
306
  *rcurr = r->first,
192
307
  *xcurr = x->first;
@@ -199,6 +314,7 @@ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseD
199
314
  if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
200
315
 
201
316
  if (rec) {
317
+ std::list<LIST*> temp_vals;
202
318
  while (lcurr || rcurr) {
203
319
  size_t key;
204
320
  LIST* val = nm::list::create();
@@ -218,13 +334,19 @@ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseD
218
334
  rcurr = rcurr->next;
219
335
  }
220
336
 
221
- if (!val->first) nm::list::del(val, 0); // empty list -- don't insert
222
- else xcurr = nm::list::insert_helper(x, xcurr, key, val);
223
337
 
338
+ if (!val->first) nm::list::del(val, 0); // empty list -- don't insert
339
+ else {
340
+ nm_list_storage_register_list(val, rec-1);
341
+ temp_vals.push_front(val);
342
+ xcurr = nm::list::insert_helper(x, xcurr, key, val);
343
+ }
224
344
  if (rcurr && rcurr->key - right.offset(rec) >= result.ref_shape(rec)) rcurr = NULL;
225
345
  if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
226
346
  }
347
+ __nm_list_storage_unregister_temp_list_list(temp_vals, rec-1);
227
348
  } else {
349
+ std::list<VALUE*> temp_vals;
228
350
  while (lcurr || rcurr) {
229
351
  size_t key;
230
352
  VALUE val;
@@ -234,7 +356,7 @@ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseD
234
356
  key = lcurr->key - left.offset(rec);
235
357
  lcurr = lcurr->next;
236
358
  } else if (!lcurr || (rcurr && (rcurr->key - right.offset(rec) < lcurr->key - left.offset(rec)))) {
237
- val = rb_yield_values(2, left.init_obj(), rubyobj_from_cval(rcurr->val, right.dtype()).rval);
359
+ val = rb_yield_values(2, left.init_obj(), rubyobj_from_cval(rcurr->val, right.dtype()).rval);
238
360
  key = rcurr->key - right.offset(rec);
239
361
  rcurr = rcurr->next;
240
362
  } else { // == and both present
@@ -243,15 +365,35 @@ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseD
243
365
  lcurr = lcurr->next;
244
366
  rcurr = rcurr->next;
245
367
  }
246
- if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue)
368
+
369
+ nm_register_value(val);
370
+
371
+ if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue) {
247
372
  xcurr = nm::list::insert_helper(x, xcurr, key, val);
373
+ temp_vals.push_front(reinterpret_cast<VALUE*>(xcurr->val));
374
+ nm_register_value(*reinterpret_cast<VALUE*>(xcurr->val));
375
+ }
376
+
377
+ nm_unregister_value(val);
248
378
 
249
379
  if (rcurr && rcurr->key - right.offset(rec) >= result.ref_shape(rec)) rcurr = NULL;
250
380
  if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL;
251
381
  }
382
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
383
+ }
384
+
385
+ if (left.dtype() == nm::RUBYOBJ) {
386
+ nm_list_storage_unregister_list(l, rec);
387
+ }
388
+ if (right.dtype() == nm::RUBYOBJ) {
389
+ nm_list_storage_unregister_list(r, rec);
390
+ }
391
+ if (result.dtype() == nm::RUBYOBJ) {
392
+ nm_list_storage_unregister_list(x, rec);
252
393
  }
253
394
  }
254
395
 
396
+
255
397
  /*
256
398
  * Recursive function, sets multiple values in a matrix from multiple source values. Also handles removal; returns true
257
399
  * if the recursion results in an empty list at that level (which signals that the current parent should be removed).
@@ -266,6 +408,12 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
266
408
  using nm::list::insert_after;
267
409
  size_t* offsets = dest->offset;
268
410
 
411
+ nm_list_storage_register(dest);
412
+ if (dest->dtype == nm::RUBYOBJ) {
413
+ nm_register_values(reinterpret_cast<VALUE*>(v), v_size);
414
+ nm_list_storage_register_list(l, dest->dim - n - 1);
415
+ }
416
+
269
417
  // drill down into the structure
270
418
  NODE* prev = find_preceding_from_list(l, coords[n] + offsets[n]);
271
419
  NODE* node = NULL;
@@ -286,13 +434,16 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
286
434
  }
287
435
 
288
436
  // At this point, it's guaranteed that there is a list here matching key.
289
-
437
+ std::list<LIST*> temp_lists;
290
438
  while (node) {
291
439
  // Recurse down into the list. If it returns true, it's empty, so we need to delete it.
292
440
  bool remove_parent = slice_set(dest, reinterpret_cast<LIST*>(node->val), coords, lengths, n+1, v, v_size, v_offset);
293
-
441
+ if (dest->dtype == nm::RUBYOBJ) {
442
+ temp_lists.push_front(reinterpret_cast<LIST*>(node->val));
443
+ nm_list_storage_register_list(reinterpret_cast<LIST*>(node->val), dest->dim - n - 2);
444
+ }
294
445
  if (remove_parent) {
295
- xfree(remove_by_node(l, prev, node));
446
+ NM_FREE(remove_by_node(l, prev, node));
296
447
  if (prev) node = prev->next ? prev->next : NULL;
297
448
  else node = l->first ? l->first : NULL;
298
449
  } else { // move forward
@@ -313,12 +464,13 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
313
464
  }
314
465
  }
315
466
  }
467
+ __nm_list_storage_unregister_temp_list_list(temp_lists, dest->dim - n - 2);
316
468
 
317
469
  } else {
318
470
 
319
471
  size_t i = 0;
320
472
  size_t key = i + offsets[n] + coords[n];
321
-
473
+ std::list<VALUE*> temp_vals;
322
474
  while (i < lengths[n]) {
323
475
  // Make sure we have an element to work with
324
476
  if (v_offset >= v_size) v_offset %= v_size;
@@ -327,7 +479,7 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
327
479
  if (node->key == key) {
328
480
  if (v[v_offset] == *reinterpret_cast<D*>(dest->default_val)) { // remove zero value
329
481
 
330
- xfree(remove_by_node(l, (prev ? prev : l->first), node));
482
+ NM_FREE(remove_by_node(l, (prev ? prev : l->first), node));
331
483
 
332
484
  if (prev) node = prev->next ? prev->next : NULL;
333
485
  else node = l->first ? l->first : NULL;
@@ -338,7 +490,12 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
338
490
  node = node->next ? node->next : NULL;
339
491
  }
340
492
  } else if (node->key > key) {
341
- D* nv = ALLOC(D); *nv = v[v_offset];
493
+ D* nv = NM_ALLOC(D); *nv = v[v_offset++];
494
+ if (dest->dtype == nm::RUBYOBJ) {
495
+ nm_register_value(*reinterpret_cast<VALUE*>(nv));
496
+ temp_vals.push_front(reinterpret_cast<VALUE*>(nv));
497
+ }
498
+
342
499
  if (prev) node = insert_after(prev, key, nv);
343
500
  else node = insert_first_node(l, key, nv, sizeof(D));
344
501
 
@@ -346,7 +503,11 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
346
503
  node = prev->next ? prev->next : NULL;
347
504
  }
348
505
  } else { // no node -- insert a new one
349
- D* nv = ALLOC(D); *nv = v[v_offset];
506
+ D* nv = NM_ALLOC(D); *nv = v[v_offset++];
507
+ if (dest->dtype == nm::RUBYOBJ) {
508
+ nm_register_value(*reinterpret_cast<VALUE*>(nv));
509
+ temp_vals.push_front(reinterpret_cast<VALUE*>(nv));
510
+ }
350
511
  if (prev) node = insert_after(prev, key, nv);
351
512
  else node = insert_first_node(l, key, nv, sizeof(D));
352
513
 
@@ -356,7 +517,14 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
356
517
 
357
518
  ++i; ++key;
358
519
  }
520
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
521
+ }
522
+
523
+ if (dest->dtype == nm::RUBYOBJ) {
524
+ nm_unregister_values(reinterpret_cast<VALUE*>(v), v_size);
525
+ nm_list_storage_unregister_list(l, dest->dim - n - 1);
359
526
  }
527
+ nm_list_storage_unregister(dest);
360
528
 
361
529
  return (l->first) ? false : true;
362
530
  }
@@ -364,8 +532,10 @@ static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengt
364
532
 
365
533
  template <typename D>
366
534
  void set(VALUE left, SLICE* slice, VALUE right) {
535
+ NM_CONSERVATIVE(nm_register_value(left));
536
+ NM_CONSERVATIVE(nm_register_value(right));
367
537
  LIST_STORAGE* s = NM_STORAGE_LIST(left);
368
-
538
+
369
539
  std::pair<NMATRIX*,bool> nm_and_free =
370
540
  interpret_arg_as_dense_nmatrix(right, NM_DTYPE(left));
371
541
 
@@ -379,17 +549,27 @@ void set(VALUE left, SLICE* slice, VALUE right) {
379
549
  v_size = nm_storage_count_max_elements(t);
380
550
 
381
551
  } else if (TYPE(right) == T_ARRAY) {
552
+ nm_register_nmatrix(nm_and_free.first);
382
553
  v_size = RARRAY_LEN(right);
383
- v = ALLOC_N(D, v_size);
554
+ v = NM_ALLOC_N(D, v_size);
555
+ if (NM_DTYPE(left) == nm::RUBYOBJ)
556
+ nm_register_values(reinterpret_cast<VALUE*>(v), v_size);
557
+
384
558
  for (size_t m = 0; m < v_size; ++m) {
385
559
  rubyval_to_cval(rb_ary_entry(right, m), s->dtype, &(v[m]));
386
560
  }
561
+ if (NM_DTYPE(left) == nm::RUBYOBJ)
562
+ nm_unregister_values(reinterpret_cast<VALUE*>(v), v_size);
563
+
387
564
  } else {
565
+ nm_register_nmatrix(nm_and_free.first);
388
566
  v = reinterpret_cast<D*>(rubyobj_to_cval(right, NM_DTYPE(left)));
389
567
  }
390
568
 
391
569
  if (v_size == 1 && *v == *reinterpret_cast<D*>(s->default_val)) {
392
- nm::list::remove_recursive(s->rows, slice->coords, s->offset, slice->lengths, 0, s->dim);
570
+ if (*reinterpret_cast<D*>(nm_list_storage_get(s, slice)) != *reinterpret_cast<D*>(s->default_val)) {
571
+ nm::list::remove_recursive(s->rows, slice->coords, s->offset, slice->lengths, 0, s->dim);
572
+ }
393
573
  } else if (slice->single) {
394
574
  slice_set_single(s, s->rows, reinterpret_cast<void*>(v), slice->coords, slice->lengths, 0);
395
575
  } else {
@@ -403,7 +583,12 @@ void set(VALUE left, SLICE* slice, VALUE right) {
403
583
  if (nm_and_free.second) {
404
584
  nm_delete(nm_and_free.first);
405
585
  }
406
- } else xfree(v);
586
+ } else {
587
+ NM_FREE(v);
588
+ nm_unregister_nmatrix(nm_and_free.first);
589
+ }
590
+ NM_CONSERVATIVE(nm_unregister_value(left));
591
+ NM_CONSERVATIVE(nm_unregister_value(right));
407
592
  }
408
593
 
409
594
  /*
@@ -411,7 +596,7 @@ void set(VALUE left, SLICE* slice, VALUE right) {
411
596
  */
412
597
  template <typename D>
413
598
  void init_default(LIST_STORAGE* s) {
414
- s->default_val = ALLOC(D);
599
+ s->default_val = NM_ALLOC(D);
415
600
  *reinterpret_cast<D*>(s->default_val) = 0;
416
601
  }
417
602
 
@@ -438,13 +623,13 @@ extern "C" {
438
623
  * new storage. You don't need to free them, and you shouldn't re-use them.
439
624
  */
440
625
  LIST_STORAGE* nm_list_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, void* init_val) {
441
- LIST_STORAGE* s = ALLOC( LIST_STORAGE );
626
+ LIST_STORAGE* s = NM_ALLOC( LIST_STORAGE );
442
627
 
443
628
  s->dim = dim;
444
629
  s->shape = shape;
445
630
  s->dtype = dtype;
446
631
 
447
- s->offset = ALLOC_N(size_t, s->dim);
632
+ s->offset = NM_ALLOC_N(size_t, s->dim);
448
633
  memset(s->offset, 0, s->dim * sizeof(size_t));
449
634
 
450
635
  s->rows = nm::list::create();
@@ -461,7 +646,7 @@ LIST_STORAGE* nm_list_storage_create(nm::dtype_t dtype, size_t* shape, size_t di
461
646
  }
462
647
 
463
648
  /*
464
- * Documentation goes here.
649
+ * Destructor for list storage.
465
650
  */
466
651
  void nm_list_storage_delete(STORAGE* s) {
467
652
  if (s) {
@@ -469,30 +654,30 @@ void nm_list_storage_delete(STORAGE* s) {
469
654
  if (storage->count-- == 1) {
470
655
  nm::list::del( storage->rows, storage->dim - 1 );
471
656
 
472
- xfree(storage->shape);
473
- xfree(storage->offset);
474
- xfree(storage->default_val);
475
- xfree(s);
657
+ NM_FREE(storage->shape);
658
+ NM_FREE(storage->offset);
659
+ NM_FREE(storage->default_val);
660
+ NM_FREE(s);
476
661
  }
477
662
  }
478
663
  }
479
664
 
480
665
  /*
481
- * Documentation goes here.
666
+ * Destructor for a list storage reference slice.
482
667
  */
483
668
  void nm_list_storage_delete_ref(STORAGE* s) {
484
669
  if (s) {
485
670
  LIST_STORAGE* storage = (LIST_STORAGE*)s;
486
671
 
487
672
  nm_list_storage_delete( reinterpret_cast<STORAGE*>(storage->src ) );
488
- xfree(storage->shape);
489
- xfree(storage->offset);
490
- xfree(s);
673
+ NM_FREE(storage->shape);
674
+ NM_FREE(storage->offset);
675
+ NM_FREE(s);
491
676
  }
492
677
  }
493
678
 
494
679
  /*
495
- * Documentation goes here.
680
+ * GC mark function for list storage.
496
681
  */
497
682
  void nm_list_storage_mark(STORAGE* storage_base) {
498
683
  LIST_STORAGE* storage = (LIST_STORAGE*)storage_base;
@@ -503,6 +688,85 @@ void nm_list_storage_mark(STORAGE* storage_base) {
503
688
  }
504
689
  }
505
690
 
691
+ static void __nm_list_storage_unregister_temp_value_list(std::list<VALUE*>& temp_vals) {
692
+ for (std::list<VALUE*>::iterator it = temp_vals.begin(); it != temp_vals.end(); ++it) {
693
+ nm_unregister_value(**it);
694
+ }
695
+ }
696
+
697
+ static void __nm_list_storage_unregister_temp_list_list(std::list<LIST*>& temp_vals, size_t recursions) {
698
+ for (std::list<LIST*>::iterator it = temp_vals.begin(); it != temp_vals.end(); ++it) {
699
+ nm_list_storage_unregister_list(*it, recursions);
700
+ }
701
+ }
702
+
703
+ void nm_list_storage_register_node(const NODE* curr) {
704
+ nm_register_value(*reinterpret_cast<VALUE*>(curr->val));
705
+ }
706
+
707
+ void nm_list_storage_unregister_node(const NODE* curr) {
708
+ nm_unregister_value(*reinterpret_cast<VALUE*>(curr->val));
709
+ }
710
+
711
+ /**
712
+ * Gets rid of all instances of a given node in the registration list.
713
+ * Sometimes a node will get deleted and replaced deep in a recursion, but
714
+ * further up it will still get registered. This leads to a potential read
715
+ * after free during the GC marking. This function completely clears out a
716
+ * node so that this won't happen.
717
+ */
718
+ void nm_list_storage_completely_unregister_node(const NODE* curr) {
719
+ nm_completely_unregister_value(*reinterpret_cast<VALUE*>(curr->val));
720
+ }
721
+
722
+ void nm_list_storage_register_list(const LIST* list, size_t recursions) {
723
+ NODE* next;
724
+ if (!list) return;
725
+ NODE* curr = list->first;
726
+
727
+ while (curr != NULL) {
728
+ next = curr->next;
729
+ if (recursions == 0) {
730
+ nm_list_storage_register_node(curr);
731
+ } else {
732
+ nm_list_storage_register_list(reinterpret_cast<LIST*>(curr->val), recursions - 1);
733
+ }
734
+ curr = next;
735
+ }
736
+ }
737
+
738
+ void nm_list_storage_unregister_list(const LIST* list, size_t recursions) {
739
+ NODE* next;
740
+ if (!list) return;
741
+ NODE* curr = list->first;
742
+
743
+ while (curr != NULL) {
744
+ next = curr->next;
745
+ if (recursions == 0) {
746
+ nm_list_storage_unregister_node(curr);
747
+ } else {
748
+ nm_list_storage_unregister_list(reinterpret_cast<LIST*>(curr->val), recursions - 1);
749
+ }
750
+ curr = next;
751
+ }
752
+ }
753
+
754
+ void nm_list_storage_register(const STORAGE* s) {
755
+ const LIST_STORAGE* storage = reinterpret_cast<const LIST_STORAGE*>(s);
756
+ if (storage && storage->dtype == nm::RUBYOBJ) {
757
+ nm_register_value(*reinterpret_cast<VALUE*>(storage->default_val));
758
+ nm_list_storage_register_list(storage->rows, storage->dim - 1);
759
+ }
760
+ }
761
+
762
+ void nm_list_storage_unregister(const STORAGE* s) {
763
+ const LIST_STORAGE* storage = reinterpret_cast<const LIST_STORAGE*>(s);
764
+ if (storage && storage->dtype == nm::RUBYOBJ) {
765
+ nm_unregister_value(*reinterpret_cast<VALUE*>(storage->default_val));
766
+ nm_list_storage_unregister_list(storage->rows, storage->dim - 1);
767
+ }
768
+ }
769
+
506
770
  ///////////////
507
771
  // Accessors //
508
772
  ///////////////
@@ -510,8 +774,7 @@ void nm_list_storage_mark(STORAGE* storage_base) {
510
774
  /*
511
775
  * Documentation goes here.
512
776
  */
513
- static NODE* list_storage_get_single_node(LIST_STORAGE* s, SLICE* slice)
514
- {
777
+ static NODE* list_storage_get_single_node(LIST_STORAGE* s, SLICE* slice) {
515
778
  size_t r;
516
779
  LIST* l = s->rows;
517
780
  NODE* n;
@@ -532,6 +795,7 @@ static NODE* list_storage_get_single_node(LIST_STORAGE* s, SLICE* slice)
532
795
  */
533
796
  static void each_empty_with_indices_r(nm::list_storage::RecurseData& s, size_t rec, VALUE& stack) {
534
797
  VALUE empty = s.dtype() == nm::RUBYOBJ ? *reinterpret_cast<VALUE*>(s.init()) : s.init_obj();
798
+ NM_CONSERVATIVE(nm_register_value(stack));
535
799
 
536
800
  if (rec) {
537
801
  for (long index = 0; index < s.ref_shape(rec); ++index) {
@@ -549,12 +813,16 @@ static void each_empty_with_indices_r(nm::list_storage::RecurseData& s, size_t r
549
813
  }
550
814
  rb_ary_shift(stack);
551
815
  }
816
+ NM_CONSERVATIVE(nm_unregister_value(stack));
552
817
  }
553
818
 
554
819
  /*
555
820
  * Recursive helper function for each_with_indices, based on nm_list_storage_count_elements_r.
556
821
  */
557
822
  static void each_with_indices_r(nm::list_storage::RecurseData& s, const LIST* l, size_t rec, VALUE& stack) {
823
+ if (s.dtype() == nm::RUBYOBJ)
824
+ nm_list_storage_register_list(l, rec);
825
+ NM_CONSERVATIVE(nm_register_value(stack));
558
826
  NODE* curr = l->first;
559
827
 
560
828
  size_t offset = s.offset(rec);
@@ -594,7 +862,9 @@ static void each_with_indices_r(nm::list_storage::RecurseData& s, const LIST* l,
594
862
  rb_ary_pop(stack);
595
863
  }
596
864
  }
597
-
865
+ NM_CONSERVATIVE(nm_unregister_value(stack));
866
+ if (s.dtype() == nm::RUBYOBJ)
867
+ nm_list_storage_unregister_list(l, rec);
598
868
  }
599
869
 
600
870
 
@@ -602,6 +872,10 @@ static void each_with_indices_r(nm::list_storage::RecurseData& s, const LIST* l,
602
872
  * Recursive helper function for each_stored_with_indices, based on nm_list_storage_count_elements_r.
603
873
  */
604
874
  static void each_stored_with_indices_r(nm::list_storage::RecurseData& s, const LIST* l, size_t rec, VALUE& stack) {
875
+ if (s.dtype() == nm::RUBYOBJ)
876
+ nm_list_storage_register_list(l, rec);
877
+ NM_CONSERVATIVE(nm_register_value(stack));
878
+
605
879
  NODE* curr = l->first;
606
880
 
607
881
  size_t offset = s.offset(rec);
@@ -639,6 +913,9 @@ static void each_stored_with_indices_r(nm::list_storage::RecurseData& s, const L
639
913
  if (curr && curr->key - offset >= shape) curr = NULL;
640
914
  }
641
915
  }
916
+ NM_CONSERVATIVE(nm_unregister_value(stack));
917
+ if (s.dtype() == nm::RUBYOBJ)
918
+ nm_list_storage_unregister_list(l, rec);
642
919
  }
643
920
 
644
921
 
@@ -648,7 +925,11 @@ static void each_stored_with_indices_r(nm::list_storage::RecurseData& s, const L
648
925
  */
649
926
  VALUE nm_list_each_with_indices(VALUE nmatrix, bool stored) {
650
927
 
928
+ NM_CONSERVATIVE(nm_register_value(nmatrix));
929
+
651
930
  // If we don't have a block, return an enumerator.
931
+ RETURN_SIZED_ENUMERATOR_PRE
932
+ NM_CONSERVATIVE(nm_unregister_value(nmatrix));
652
933
  RETURN_SIZED_ENUMERATOR(nmatrix, 0, 0, 0);
653
934
 
654
935
  nm::list_storage::RecurseData sdata(NM_STORAGE_LIST(nmatrix));
@@ -658,14 +939,71 @@ VALUE nm_list_each_with_indices(VALUE nmatrix, bool stored) {
658
939
  if (stored) each_stored_with_indices_r(sdata, sdata.top_level_list(), sdata.dim() - 1, stack);
659
940
  else each_with_indices_r(sdata, sdata.top_level_list(), sdata.dim() - 1, stack);
660
941
 
942
+ NM_CONSERVATIVE(nm_unregister_value(nmatrix));
661
943
  return nmatrix;
662
944
  }
663
945
 
664
946
 
947
+ /*
948
+ * map merged stored iterator. Always returns a matrix containing RubyObjects which probably needs to be casted.
949
+ */
950
+ VALUE nm_list_map_stored(VALUE left, VALUE init) {
951
+ NM_CONSERVATIVE(nm_register_value(left));
952
+ NM_CONSERVATIVE(nm_register_value(init));
953
+
954
+ bool scalar = false;
955
+
956
+ LIST_STORAGE *s = NM_STORAGE_LIST(left);
957
+
958
+ // For each matrix, if it's a reference, we want to deal directly with the original (with appropriate offsetting)
959
+ nm::list_storage::RecurseData sdata(s);
960
+
961
+ void* scalar_init = NULL;
962
+
963
+ //if (!rb_block_given_p()) {
964
+ // rb_raise(rb_eNotImpError, "RETURN_SIZED_ENUMERATOR probably won't work for a map_merged since no merged object is created");
965
+ //}
966
+ // If we don't have a block, return an enumerator.
967
+ RETURN_SIZED_ENUMERATOR_PRE
968
+ NM_CONSERVATIVE(nm_unregister_value(left));
969
+ NM_CONSERVATIVE(nm_unregister_value(init));
970
+ RETURN_SIZED_ENUMERATOR(left, 0, 0, 0); // FIXME: Test this. Probably won't work. Enable above code instead.
971
+
972
+ // Figure out default value if none provided by the user
973
+ if (init == Qnil) {
974
+ nm_unregister_value(init);
975
+ init = rb_yield_values(1, sdata.init_obj());
976
+ nm_register_value(init);
977
+ }
978
+ // Allocate a new shape array for the resulting matrix.
979
+ void* init_val = NM_ALLOC(VALUE);
980
+ memcpy(init_val, &init, sizeof(VALUE));
981
+ nm_register_value(*reinterpret_cast<VALUE*>(init_val));
982
+
983
+ NMATRIX* result = nm_create(nm::LIST_STORE, nm_list_storage_create(nm::RUBYOBJ, sdata.copy_alloc_shape(), s->dim, init_val));
984
+ LIST_STORAGE* r = reinterpret_cast<LIST_STORAGE*>(result->storage);
985
+ nm::list_storage::RecurseData rdata(r, init);
986
+ nm_register_nmatrix(result);
987
+ map_stored_r(rdata, sdata, rdata.top_level_list(), sdata.top_level_list(), sdata.dim() - 1);
988
+
989
+ VALUE to_return = Data_Wrap_Struct(CLASS_OF(left), nm_mark, nm_delete, result);
990
+
991
+ nm_unregister_nmatrix(result);
992
+ nm_unregister_value(*reinterpret_cast<VALUE*>(init_val));
993
+ NM_CONSERVATIVE(nm_unregister_value(init));
994
+ NM_CONSERVATIVE(nm_unregister_value(left));
995
+
996
+ return to_return;
997
+ }
998
+
999
+
665
1000
  /*
666
1001
  * map merged stored iterator. Always returns a matrix containing RubyObjects which probably needs to be casted.
667
1002
  */
668
1003
  VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
1004
+ NM_CONSERVATIVE(nm_register_value(left));
1005
+ NM_CONSERVATIVE(nm_register_value(right));
1006
+ NM_CONSERVATIVE(nm_register_value(init));
669
1007
 
670
1008
  bool scalar = false;
671
1009
 
@@ -679,8 +1017,7 @@ VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
679
1017
 
680
1018
  // right might be a scalar, in which case this is a scalar operation.
681
1019
  if (TYPE(right) != T_DATA || (RDATA(right)->dfree != (RUBY_DATA_FUNC)nm_delete && RDATA(right)->dfree != (RUBY_DATA_FUNC)nm_delete_ref)) {
682
- nm::dtype_t r_dtype = nm_dtype_min(right);
683
-
1020
+ nm::dtype_t r_dtype = Upcast[NM_DTYPE(left)][nm_dtype_min(right)];
684
1021
  scalar_init = rubyobj_to_cval(right, r_dtype); // make a copy of right
685
1022
 
686
1023
  t = reinterpret_cast<LIST_STORAGE*>(nm_list_storage_create(r_dtype, sdata.copy_alloc_shape(), s->dim, scalar_init));
@@ -693,26 +1030,43 @@ VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
693
1030
  // rb_raise(rb_eNotImpError, "RETURN_SIZED_ENUMERATOR probably won't work for a map_merged since no merged object is created");
694
1031
  //}
695
1032
  // If we don't have a block, return an enumerator.
1033
+ RETURN_SIZED_ENUMERATOR_PRE
1034
+ NM_CONSERVATIVE(nm_unregister_value(left));
1035
+ NM_CONSERVATIVE(nm_unregister_value(right));
1036
+ NM_CONSERVATIVE(nm_unregister_value(init));
696
1037
  RETURN_SIZED_ENUMERATOR(left, 0, 0, 0); // FIXME: Test this. Probably won't work. Enable above code instead.
697
1038
 
698
1039
  // Figure out default value if none provided by the user
699
- nm::list_storage::RecurseData tdata(t);
700
- if (init == Qnil) init = rb_yield_values(2, sdata.init_obj(), tdata.init_obj());
1040
+ nm::list_storage::RecurseData& tdata = *(new nm::list_storage::RecurseData(t)); //FIXME: this is a hack to make sure that we can run the destructor before nm_list_storage_delete(t) below.
1041
+ if (init == Qnil) {
1042
+ nm_unregister_value(init);
1043
+ init = rb_yield_values(2, sdata.init_obj(), tdata.init_obj());
1044
+ nm_register_value(init);
1045
+ }
701
1046
 
702
- // Allocate a new shape array for the resulting matrix.
703
- void* init_val = ALLOC(VALUE);
1047
+ // Allocate a new shape array for the resulting matrix.
1048
+ void* init_val = NM_ALLOC(VALUE);
704
1049
  memcpy(init_val, &init, sizeof(VALUE));
1050
+ nm_register_value(*reinterpret_cast<VALUE*>(init_val));
705
1051
 
706
1052
  NMATRIX* result = nm_create(nm::LIST_STORE, nm_list_storage_create(nm::RUBYOBJ, sdata.copy_alloc_shape(), s->dim, init_val));
707
1053
  LIST_STORAGE* r = reinterpret_cast<LIST_STORAGE*>(result->storage);
708
1054
  nm::list_storage::RecurseData rdata(r, init);
709
-
710
1055
  map_merged_stored_r(rdata, sdata, tdata, rdata.top_level_list(), sdata.top_level_list(), tdata.top_level_list(), sdata.dim() - 1);
711
1056
 
1057
+ delete &tdata;
712
1058
  // If we are working with a scalar operation
713
1059
  if (scalar) nm_list_storage_delete(t);
714
1060
 
715
- return Data_Wrap_Struct(CLASS_OF(left), nm_mark, nm_delete, result);
1061
+ VALUE to_return = Data_Wrap_Struct(CLASS_OF(left), nm_mark, nm_delete, result);
1062
+
1063
+ nm_unregister_value(*reinterpret_cast<VALUE*>(init_val));
1064
+
1065
+ NM_CONSERVATIVE(nm_unregister_value(init));
1066
+ NM_CONSERVATIVE(nm_unregister_value(right));
1067
+ NM_CONSERVATIVE(nm_unregister_value(left));
1068
+
1069
+ return to_return;
716
1070
  }
717
1071
 
718
1072
 
@@ -720,13 +1074,14 @@ VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
720
1074
  * Copy a slice of a list matrix into a regular list matrix.
721
1075
  */
722
1076
  static LIST* slice_copy(const LIST_STORAGE* src, LIST* src_rows, size_t* coords, size_t* lengths, size_t n) {
723
-
1077
+ nm_list_storage_register(src);
724
1078
  void *val = NULL;
725
1079
  int key;
726
1080
 
727
1081
  LIST* dst_rows = nm::list::create();
728
1082
  NODE* src_node = src_rows->first;
729
-
1083
+ std::list<VALUE*> temp_vals;
1084
+ std::list<LIST*> temp_lists;
730
1085
  while (src_node) {
731
1086
  key = src_node->key - (src->offset[n] + coords[n]);
732
1087
 
@@ -737,16 +1092,28 @@ static LIST* slice_copy(const LIST_STORAGE* src, LIST* src_rows, size_t* coords,
737
1092
  coords,
738
1093
  lengths,
739
1094
  n + 1 );
740
-
741
- if (val) { nm::list::insert_copy(dst_rows, false, key, val, sizeof(LIST)); }
1095
+ if (val) {
1096
+ if (src->dtype == nm::RUBYOBJ) {
1097
+ nm_list_storage_register_list(reinterpret_cast<LIST*>(val), src->dim - n - 2);
1098
+ temp_lists.push_front(reinterpret_cast<LIST*>(val));
1099
+ }
1100
+ nm::list::insert_copy(dst_rows, false, key, val, sizeof(LIST));
1101
+ }
1102
+ } else { // matches src->dim - n > 1
1103
+ if (src->dtype == nm::RUBYOBJ) {
1104
+ nm_register_value(*reinterpret_cast<VALUE*>(src_node->val));
1105
+ temp_vals.push_front(reinterpret_cast<VALUE*>(src_node->val));
1106
+ }
1107
+ nm::list::insert_copy(dst_rows, false, key, src_node->val, DTYPE_SIZES[src->dtype]);
742
1108
  }
743
-
744
- else nm::list::insert_copy(dst_rows, false, key, src_node->val, DTYPE_SIZES[src->dtype]);
745
1109
  }
746
-
747
1110
  src_node = src_node->next;
1111
+ }
1112
+ if (src->dtype == nm::RUBYOBJ) {
1113
+ __nm_list_storage_unregister_temp_list_list(temp_lists, src->dim - n - 2);
1114
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
748
1115
  }
749
-
1116
+ nm_list_storage_unregister(src);
750
1117
  return dst_rows;
751
1118
  }
752
1119
 
@@ -756,21 +1123,31 @@ static LIST* slice_copy(const LIST_STORAGE* src, LIST* src_rows, size_t* coords,
756
1123
  void* nm_list_storage_get(const STORAGE* storage, SLICE* slice) {
757
1124
  LIST_STORAGE* s = (LIST_STORAGE*)storage;
758
1125
  LIST_STORAGE* ns = NULL;
759
- NODE* n;
1126
+
1127
+ nm_list_storage_register(s);
760
1128
 
761
1129
  if (slice->single) {
762
- n = list_storage_get_single_node(s, slice);
1130
+ NODE* n = list_storage_get_single_node(s, slice);
1131
+ nm_list_storage_unregister(s);
763
1132
  return (n ? n->val : s->default_val);
1133
+
764
1134
  } else {
765
- void *init_val = ALLOC_N(char, DTYPE_SIZES[s->dtype]);
1135
+ void *init_val = NM_ALLOC_N(char, DTYPE_SIZES[s->dtype]);
766
1136
  memcpy(init_val, s->default_val, DTYPE_SIZES[s->dtype]);
1137
+ if (s->dtype == nm::RUBYOBJ)
1138
+ nm_register_value(*reinterpret_cast<VALUE*>(init_val));
767
1139
 
768
- size_t *shape = ALLOC_N(size_t, s->dim);
1140
+ size_t *shape = NM_ALLOC_N(size_t, s->dim);
769
1141
  memcpy(shape, slice->lengths, sizeof(size_t) * s->dim);
770
1142
 
771
1143
  ns = nm_list_storage_create(s->dtype, shape, s->dim, init_val);
772
-
1144
+
773
1145
  ns->rows = slice_copy(s, s->rows, slice->coords, slice->lengths, 0);
1146
+
1147
+ if (s->dtype == nm::RUBYOBJ)
1148
+ nm_unregister_value(*reinterpret_cast<VALUE*>(init_val));
1149
+ nm_list_storage_unregister(s);
1150
+
774
1151
  return ns;
775
1152
  }
776
1153
  }
@@ -782,20 +1159,21 @@ void* nm_list_storage_get(const STORAGE* storage, SLICE* slice) {
782
1159
  void* nm_list_storage_ref(const STORAGE* storage, SLICE* slice) {
783
1160
  LIST_STORAGE* s = (LIST_STORAGE*)storage;
784
1161
  LIST_STORAGE* ns = NULL;
785
- NODE* n;
1162
+ nm_list_storage_register(s);
786
1163
 
787
1164
  //TODO: It needs a refactoring.
788
1165
  if (slice->single) {
789
- n = list_storage_get_single_node(s, slice);
1166
+ NODE* n = list_storage_get_single_node(s, slice);
1167
+ nm_list_storage_unregister(s);
790
1168
  return (n ? n->val : s->default_val);
791
1169
  }
792
1170
  else {
793
- ns = ALLOC( LIST_STORAGE );
1171
+ ns = NM_ALLOC( LIST_STORAGE );
794
1172
 
795
1173
  ns->dim = s->dim;
796
1174
  ns->dtype = s->dtype;
797
- ns->offset = ALLOC_N(size_t, ns->dim);
798
- ns->shape = ALLOC_N(size_t, ns->dim);
1175
+ ns->offset = NM_ALLOC_N(size_t, ns->dim);
1176
+ ns->shape = NM_ALLOC_N(size_t, ns->dim);
799
1177
 
800
1178
  for (size_t i = 0; i < ns->dim; ++i) {
801
1179
  ns->offset[i] = slice->coords[i] + s->offset[i];
@@ -807,7 +1185,7 @@ void* nm_list_storage_ref(const STORAGE* storage, SLICE* slice) {
807
1185
 
808
1186
  s->src->count++;
809
1187
  ns->src = s->src;
810
-
1188
+ nm_list_storage_unregister(s);
811
1189
  return ns;
812
1190
  }
813
1191
  }
@@ -817,10 +1195,16 @@ void* nm_list_storage_ref(const STORAGE* storage, SLICE* slice) {
817
1195
  * Recursive function, sets multiple values in a matrix from a single source value.
818
1196
  */
819
1197
  static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coords, size_t* lengths, size_t n) {
1198
+ nm_list_storage_register(dest);
1199
+ if (dest->dtype == nm::RUBYOBJ) {
1200
+ nm_register_value(*reinterpret_cast<VALUE*>(val));
1201
+ nm_list_storage_register_list(l, dest->dim - n - 1);
1202
+ }
820
1203
 
821
1204
  // drill down into the structure
822
1205
  NODE* node = NULL;
823
1206
  if (dest->dim - n > 1) {
1207
+ std::list<LIST*> temp_nodes;
824
1208
  for (size_t i = 0; i < lengths[n]; ++i) {
825
1209
 
826
1210
  size_t key = i + dest->offset[n] + coords[n];
@@ -833,10 +1217,17 @@ static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coo
833
1217
  node = node->next; // correct rank already exists.
834
1218
  }
835
1219
 
1220
+ if (dest->dtype == nm::RUBYOBJ) {
1221
+ temp_nodes.push_front(reinterpret_cast<LIST*>(node->val));
1222
+ nm_list_storage_register_list(reinterpret_cast<LIST*>(node->val), dest->dim - n - 2);
1223
+ }
1224
+
836
1225
  // cast it to a list and recurse
837
1226
  slice_set_single(dest, reinterpret_cast<LIST*>(node->val), val, coords, lengths, n + 1);
838
1227
  }
1228
+ __nm_list_storage_unregister_temp_list_list(temp_nodes, dest->dim - n - 2);
839
1229
  } else {
1230
+ std::list<VALUE*> temp_vals;
840
1231
  for (size_t i = 0; i < lengths[n]; ++i) {
841
1232
 
842
1233
  size_t key = i + dest->offset[n] + coords[n];
@@ -846,7 +1237,18 @@ static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coo
846
1237
  } else {
847
1238
  node = nm::list::replace_insert_after(node, key, val, true, DTYPE_SIZES[dest->dtype]);
848
1239
  }
1240
+ if (dest->dtype == nm::RUBYOBJ) {
1241
+ temp_vals.push_front(reinterpret_cast<VALUE*>(node->val));
1242
+ nm_register_value(*reinterpret_cast<VALUE*>(node->val));
1243
+ }
849
1244
  }
1245
+ __nm_list_storage_unregister_temp_value_list(temp_vals);
1246
+ }
1247
+
1248
+ nm_list_storage_unregister(dest);
1249
+ if (dest->dtype == nm::RUBYOBJ) {
1250
+ nm_unregister_value(*reinterpret_cast<VALUE*>(val));
1251
+ nm_list_storage_unregister_list(l, dest->dim - n - 1);
850
1252
  }
851
1253
  }
852
1254
 
@@ -870,6 +1272,9 @@ void nm_list_storage_set(VALUE left, SLICE* slice, VALUE right) {
870
1272
  */
871
1273
  NODE* nm_list_storage_insert(STORAGE* storage, SLICE* slice, void* val) {
872
1274
  LIST_STORAGE* s = (LIST_STORAGE*)storage;
1275
+ nm_list_storage_register(s);
1276
+ if (s->dtype == nm::RUBYOBJ)
1277
+ nm_register_value(*reinterpret_cast<VALUE*>(val));
873
1278
  // Pretend dims = 2
874
1279
  // Then coords is going to be size 2
875
1280
  // So we need to find out if some key already exists
@@ -878,12 +1283,16 @@ NODE* nm_list_storage_insert(STORAGE* storage, SLICE* slice, void* val) {
878
1283
  LIST* l = s->rows;
879
1284
 
880
1285
  // drill down into the structure
881
- for (r = s->dim; r > 1; --r) {
882
- n = nm::list::insert(l, false, s->offset[s->dim - r] + slice->coords[s->dim - r], nm::list::create());
1286
+ for (r = 0; r < s->dim -1; ++r) {
1287
+ n = nm::list::insert(l, false, s->offset[r] + slice->coords[s->dim - r], nm::list::create());
883
1288
  l = reinterpret_cast<LIST*>(n->val);
884
1289
  }
885
1290
 
886
- return nm::list::insert(l, true, s->offset[s->dim - r] + slice->coords[s->dim - r], val);
1291
+ nm_list_storage_unregister(s);
1292
+ if (s->dtype == nm::RUBYOBJ)
1293
+ nm_unregister_value(*reinterpret_cast<VALUE*>(val));
1294
+
1295
+ return nm::list::insert(l, true, s->offset[r] + slice->coords[r], val);
887
1296
  }
888
1297
 
889
1298
  /*
@@ -937,10 +1346,10 @@ STORAGE* nm_list_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, siz
937
1346
  * it's a sparse matrix.
938
1347
  */
939
1348
  VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const nm::dtype_t dtype) {
940
-
1349
+ nm_list_storage_register(s);
941
1350
  // Get the default value for the list storage.
942
1351
  VALUE default_value = rubyobj_from_cval(s->default_val, dtype).rval;
943
-
1352
+ nm_list_storage_unregister(s);
944
1353
  // Recursively copy each dimension of the matrix into a nested hash.
945
1354
  return nm_list_copy_to_hash(s->rows, dtype, s->dim - 1, default_value);
946
1355
  }
@@ -1006,18 +1415,21 @@ size_t nm_list_storage_count_nd_elements(const LIST_STORAGE* s) {
1006
1415
  * List storage copy constructor C access.
1007
1416
  */
1008
1417
 
1009
- LIST_STORAGE* nm_list_storage_copy(const LIST_STORAGE* rhs)
1010
- {
1011
- size_t *shape = ALLOC_N(size_t, rhs->dim);
1418
+ LIST_STORAGE* nm_list_storage_copy(const LIST_STORAGE* rhs) {
1419
+ nm_list_storage_register(rhs);
1420
+ size_t *shape = NM_ALLOC_N(size_t, rhs->dim);
1012
1421
  memcpy(shape, rhs->shape, sizeof(size_t) * rhs->dim);
1013
1422
 
1014
- void *init_val = ALLOC_N(char, DTYPE_SIZES[rhs->dtype]);
1423
+ void *init_val = NM_ALLOC_N(char, DTYPE_SIZES[rhs->dtype]);
1015
1424
  memcpy(init_val, rhs->default_val, DTYPE_SIZES[rhs->dtype]);
1016
1425
 
1017
1426
  LIST_STORAGE* lhs = nm_list_storage_create(rhs->dtype, shape, rhs->dim, init_val);
1018
-
1427
+ nm_list_storage_register(lhs);
1428
+
1019
1429
  lhs->rows = slice_copy(rhs, rhs->rows, lhs->offset, lhs->shape, 0);
1020
1430
 
1431
+ nm_list_storage_unregister(rhs);
1432
+ nm_list_storage_unregister(lhs);
1021
1433
  return lhs;
1022
1434
  }
1023
1435
 
@@ -1057,27 +1469,31 @@ namespace list_storage {
1057
1469
  */
1058
1470
  template <typename LDType, typename RDType>
1059
1471
  static LIST_STORAGE* cast_copy(const LIST_STORAGE* rhs, dtype_t new_dtype) {
1060
-
1472
+ nm_list_storage_register(rhs);
1061
1473
  // allocate and copy shape
1062
- size_t* shape = ALLOC_N(size_t, rhs->dim);
1474
+ size_t* shape = NM_ALLOC_N(size_t, rhs->dim);
1063
1475
  memcpy(shape, rhs->shape, rhs->dim * sizeof(size_t));
1064
1476
 
1065
1477
  // copy default value
1066
- LDType* default_val = ALLOC_N(LDType, 1);
1478
+ LDType* default_val = NM_ALLOC_N(LDType, 1);
1067
1479
  *default_val = *reinterpret_cast<RDType*>(rhs->default_val);
1068
1480
 
1069
1481
  LIST_STORAGE* lhs = nm_list_storage_create(new_dtype, shape, rhs->dim, default_val);
1070
1482
  //lhs->rows = nm::list::create();
1071
1483
 
1484
+ nm_list_storage_register(lhs);
1072
1485
  // TODO: Needs optimization. When matrix is reference it is copped twice.
1073
1486
  if (rhs->src == rhs)
1074
1487
  nm::list::cast_copy_contents<LDType, RDType>(lhs->rows, rhs->rows, rhs->dim - 1);
1075
1488
  else {
1076
1489
  LIST_STORAGE *tmp = nm_list_storage_copy(rhs);
1490
+ nm_list_storage_register(tmp);
1077
1491
  nm::list::cast_copy_contents<LDType, RDType>(lhs->rows, tmp->rows, rhs->dim - 1);
1492
+ nm_list_storage_unregister(tmp);
1078
1493
  nm_list_storage_delete(tmp);
1079
1494
  }
1080
-
1495
+ nm_list_storage_unregister(lhs);
1496
+ nm_list_storage_unregister(rhs);
1081
1497
  return lhs;
1082
1498
  }
1083
1499
 
@@ -1196,13 +1612,16 @@ extern "C" {
1196
1612
  return nm_list_storage_to_hash(NM_STORAGE_LIST(self), NM_DTYPE(self));
1197
1613
  }
1198
1614
 
1199
- /*
1200
- * call-seq:
1201
- * __list_default_value__ -> ...
1202
- *
1203
- * Get the default_value property from a list matrix.
1204
- */
1205
- VALUE nm_list_default_value(VALUE self) {
1206
- return (NM_DTYPE(self) == nm::RUBYOBJ) ? *reinterpret_cast<VALUE*>(NM_DEFAULT_VAL(self)) : rubyobj_from_cval(NM_DEFAULT_VAL(self), NM_DTYPE(self)).rval;
1207
- }
1615
+ /*
1616
+ * call-seq:
1617
+ * __list_default_value__ -> ...
1618
+ *
1619
+ * Get the default_value property from a list matrix.
1620
+ */
1621
+ VALUE nm_list_default_value(VALUE self) {
1622
+ NM_CONSERVATIVE(nm_register_value(self));
1623
+ VALUE to_return = (NM_DTYPE(self) == nm::RUBYOBJ) ? *reinterpret_cast<VALUE*>(NM_DEFAULT_VAL(self)) : rubyobj_from_cval(NM_DEFAULT_VAL(self), NM_DTYPE(self)).rval;
1624
+ NM_CONSERVATIVE(nm_unregister_value(self));
1625
+ return to_return;
1626
+ }
1208
1627
  } // end of extern "C" block