Fixnum* Tuple::delete_inplace_prim(STATE, Fixnum *start, Fixnum *length, Object *obj) { native_int size = this->num_fields(); native_int len = length->to_native(); native_int lend = start->to_native(); native_int rend = lend + len; if(size == 0 || len == 0) return Fixnum::from(0); if(lend < 0 || lend >= size) { return force_as<Fixnum>(bounds_exceeded_error(state, "Tuple::delete_inplace", lend)); } if(rend < 0 || rend > size) { return force_as<Fixnum>(bounds_exceeded_error(state, "Tuple::delete_inplace", rend)); } return Fixnum::from(delete_inplace(lend, len, obj)); }
/* The Tuple#at primitive. */ Object* Tuple::at_prim(STATE, Fixnum* index_obj) { native_int index = index_obj->to_native(); if(index < 0 || num_fields() <= index) { return bounds_exceeded_error(state, "Tuple::at_prim", index); } return field[index]; }
Object* RTuple::at_prim(STATE, Fixnum* idx) { native_int index = idx->to_native(); if(index < 0 || num_fields() <= index) { return bounds_exceeded_error(state, "RTuple::at_prim", index); } return MemoryHandle::object(reinterpret_cast<VALUE>(field[index])); }
Fixnum* Tuple::delete_inplace(STATE, Fixnum *start, Fixnum *length, Object *obj) { int size = this->num_fields(); int len = length->to_native(); int lend = start->to_native(); int rend = lend + len; if(size == 0 || len == 0) return Fixnum::from(0); if(lend < 0 || lend >= size) { return force_as<Fixnum>(bounds_exceeded_error(state, "Tuple::delete_inplace", lend)); } if(rend < 0 || rend > size) { return force_as<Fixnum>(bounds_exceeded_error(state, "Tuple::delete_inplace", rend)); } int i = lend; while(i < rend) { if(this->at(state,i) == obj) { int j = i; ++i; while(i < rend) { Object *val = this->field[i]; if(val != obj) { // no need to set write_barrier since it's already // referenced to this object this->field[j] = val; ++j; } ++i; } // cleanup all the bins after i = j; while(i < rend) { this->field[i] = Qnil; ++i; } return Fixnum::from(rend-j); } ++i; } return Fixnum::from(0); }
/* The Tuple#put primitive. */ Object* Tuple::put_prim(STATE, Fixnum* index, Object* val) { native_int idx = index->to_native(); if(idx < 0 || num_fields() <= idx) { return bounds_exceeded_error(state, "Tuple::put_prim", idx); } field[idx] = val; write_barrier(state, val); return val; }
Object* RTuple::put_prim(STATE, Fixnum* idx, Object* val) { native_int index = idx->to_native(); if(index < 0 || num_fields() <= index) { return bounds_exceeded_error(state, "RTuple::put_prim", index); } reinterpret_cast<VALUE*>(field)[index] = MemoryHandle::value(val); state->memory()->write_barrier(this, val); return val; }
Tuple* Tuple::copy_from(STATE, Tuple* other, Fixnum* start, Fixnum *length, Fixnum* dest) { native_int osize = other->num_fields(); native_int size = this->num_fields(); native_int src_start = start->to_native(); native_int dst_start = dest->to_native(); native_int len = length->to_native(); // left end should be within range if(src_start < 0 || src_start > osize) { return other->bounds_exceeded_error(state, "Tuple::copy_from", src_start); } if(dst_start < 0 || dst_start > size) { return bounds_exceeded_error(state, "Tuple::copy_from", dst_start); } // length can not be negative and must fit in src/dest if(len < 0) { return other->bounds_exceeded_error(state, "Tuple::copy_from", len); } if((src_start + len) > osize) { return other->bounds_exceeded_error(state, "Tuple::copy_from", src_start + len); } if(len > (size - dst_start)) { return bounds_exceeded_error(state, "Tuple::copy_from", len); } // A memmove within the tuple if(other == this) { // No movement, no work! if(src_start == dst_start) return this; // right shift if(src_start < dst_start) { for(native_int dest_idx = dst_start + len - 1, src_idx = src_start + len - 1; src_idx >= src_start; src_idx--, dest_idx--) { this->field[dest_idx] = this->field[src_idx]; } } else { // left shift for(native_int dest_idx = dst_start, src_idx = src_start; src_idx < src_start + len; src_idx++, dest_idx++) { this->field[dest_idx] = this->field[src_idx]; } } } else { for(native_int src = src_start, dst = dst_start; src < (src_start + len); ++src, ++dst) { // Since we have carefully checked the bounds we don't need // to do it in at/put Object *obj = other->field[src]; // but this is necessary to keep the GC happy field[dst] = obj; write_barrier(state, obj); } } return this; }