/* * Borrowed this function from NArray. Handles 'each' iteration on a dense * matrix. * * Additionally, handles separately matrices containing VALUEs and matrices * containing other types of data. */ static VALUE nm_each_dense(VALUE nmatrix) { DENSE_STORAGE* s = NM_STORAGE_DENSE(nmatrix); VALUE v; size_t i; if (NM_DTYPE(nmatrix) == RUBYOBJ) { // matrix of Ruby objects -- yield those objects directly for (i = 0; i < nm_storage_count_max_elements(s); ++i) rb_yield( *((VALUE*)((char*)(s->elements) + i*DTYPE_SIZES[NM_DTYPE(nmatrix)])) ); } else { // We're going to copy the matrix element into a Ruby VALUE and then operate on it. This way user can't accidentally // modify it and cause a seg fault. for (i = 0; i < nm_storage_count_max_elements(s); ++i) { v = rubyobj_from_cval((char*)(s->elements) + i*DTYPE_SIZES[NM_DTYPE(nmatrix)], NM_DTYPE(nmatrix)).rval; rb_yield(v); // yield to the copy we made } } return nmatrix; }
/* * Recursive helper for map_merged_stored_r which handles the case where one list is empty and the other is not. */ static void map_empty_stored_r(RecurseData& result, RecurseData& s, LIST* x, const LIST* l, size_t rec, bool rev, const VALUE& t_init) { NODE *curr = l->first, *xcurr = NULL; // For reference matrices, make sure we start in the correct place. size_t offset = result.offset(rec); size_t x_shape = result.ref_shape(rec); while (curr && curr->key < offset) { curr = curr->next; } if (curr && curr->key - offset >= x_shape) curr = NULL; if (rec) { while (curr) { LIST* val = nm::list::create(); map_empty_stored_r(result, s, val, reinterpret_cast<const LIST*>(curr->val), rec-1, rev, t_init); if (!val->first) nm::list::del(val, 0); else nm::list::insert_helper(x, xcurr, curr->key - offset, val); curr = curr->next; if (curr && curr->key - offset >= x_shape) curr = NULL; } } else { while (curr) { VALUE val, s_val = rubyobj_from_cval(curr->val, s.dtype()).rval; if (rev) val = rb_yield_values(2, t_init, s_val); else val = rb_yield_values(2, s_val, t_init); if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue) xcurr = nm::list::insert_helper(x, xcurr, curr->key - offset, val); curr = curr->next; if (curr && curr->key - offset >= x_shape) curr = NULL; } } }
/* * Recursive helper function for nm_list_map_merged_stored */ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseData& right, LIST* x, const LIST* l, const LIST* r, size_t rec) { NODE *lcurr = l->first, *rcurr = r->first, *xcurr = x->first; // For reference matrices, make sure we start in the correct place. while (lcurr && lcurr->key < left.offset(rec)) { lcurr = lcurr->next; } while (rcurr && rcurr->key < right.offset(rec)) { rcurr = rcurr->next; } if (rcurr && rcurr->key - right.offset(rec) >= result.ref_shape(rec)) rcurr = NULL; if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL; if (rec) { while (lcurr || rcurr) { size_t key; LIST* val = nm::list::create(); if (!rcurr || (lcurr && (lcurr->key - left.offset(rec) < rcurr->key - right.offset(rec)))) { map_empty_stored_r(result, left, val, reinterpret_cast<const LIST*>(lcurr->val), rec-1, false, right.init_obj()); key = lcurr->key - left.offset(rec); lcurr = lcurr->next; } else if (!lcurr || (rcurr && (rcurr->key - right.offset(rec) < lcurr->key - left.offset(rec)))) { map_empty_stored_r(result, right, val, reinterpret_cast<const LIST*>(rcurr->val), rec-1, true, left.init_obj()); key = rcurr->key - right.offset(rec); rcurr = rcurr->next; } else { // == and both present map_merged_stored_r(result, left, right, val, reinterpret_cast<const LIST*>(lcurr->val), reinterpret_cast<const LIST*>(rcurr->val), rec-1); key = lcurr->key - left.offset(rec); lcurr = lcurr->next; rcurr = rcurr->next; } if (!val->first) nm::list::del(val, 0); // empty list -- don't insert else xcurr = nm::list::insert_helper(x, xcurr, key, val); if (rcurr && rcurr->key - right.offset(rec) >= result.ref_shape(rec)) rcurr = NULL; if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL; } } else { while (lcurr || rcurr) { size_t key; VALUE val; if (!rcurr || (lcurr && (lcurr->key - left.offset(rec) < rcurr->key - right.offset(rec)))) { val = rb_yield_values(2, rubyobj_from_cval(lcurr->val, left.dtype()).rval, right.init_obj()); key = lcurr->key - left.offset(rec); lcurr = lcurr->next; } else if (!lcurr || (rcurr && (rcurr->key - right.offset(rec) < lcurr->key - left.offset(rec)))) { val = rb_yield_values(2, left.init_obj(), rubyobj_from_cval(rcurr->val, right.dtype()).rval); key = rcurr->key - right.offset(rec); rcurr = rcurr->next; } else { // == and both present val = rb_yield_values(2, rubyobj_from_cval(lcurr->val, left.dtype()).rval, rubyobj_from_cval(rcurr->val, right.dtype()).rval); key = lcurr->key - left.offset(rec); lcurr = lcurr->next; rcurr = rcurr->next; } if (rb_funcall(val, rb_intern("!="), 1, result.init_obj()) == Qtrue) xcurr = nm::list::insert_helper(x, xcurr, key, val); if (rcurr && rcurr->key - right.offset(rec) >= result.ref_shape(rec)) rcurr = NULL; if (lcurr && lcurr->key - left.offset(rec) >= result.ref_shape(rec)) lcurr = NULL; } } }