Array* Array::concat(STATE, Array* other) { if(!LANGUAGE_18_ENABLED(state)) { if(is_frozen_p()) return force_as<Array>(Primitives::failure()); } native_int osize = other->size(); if(osize == 0) return this; if(LANGUAGE_18_ENABLED(state)) { if(is_frozen_p()) return force_as<Array>(Primitives::failure()); } if(osize == 1) { set(state, size(), other->get(state, 0)); return this; } native_int new_size = size() + osize; Tuple* nt = Tuple::create(state, new_size); nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0)); nt->copy_from(state, other->tuple(), other->start(), other->total(), total_); tuple(state, nt); start(state, Fixnum::from(0)); total(state, Fixnum::from(new_size)); return this; }
void test_copy_from_dest_out_of_range() { Tuple* tuple = new_tuple(); Tuple* dest = Tuple::create(state, 2); TS_ASSERT_THROWS_ASSERT(dest->copy_from(state, tuple, Fixnum::from(0), Fixnum::from(1), Fixnum::from(2)), const RubyException &e, TS_ASSERT(Exception::object_bounds_exceeded_error_p(state, e.exception))); TS_ASSERT_THROWS_ASSERT(dest->copy_from(state, tuple, Fixnum::from(0), Fixnum::from(1), Fixnum::from(-1)), const RubyException &e, TS_ASSERT(Exception::object_bounds_exceeded_error_p(state, e.exception))); }
Object* Array::set(STATE, native_int idx, Object* val) { native_int tuple_size = tuple_->num_fields(); native_int oidx = idx; idx += start_->to_native(); if(idx >= tuple_size) { if(oidx < tuple_size) { // There is enough space in the tuple for this element tuple_->lshift_inplace(state, start_); } else { // Uses the same algo as 1.8 to resize the tuple native_int new_size = tuple_size / 2; if(new_size < 3) { new_size = 3; } Tuple* nt = Tuple::create(state, new_size+idx); nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0)); tuple(state, nt); } start(state, Fixnum::from(0)); idx = oidx; } tuple_->put(state, idx, val); if(total_->to_native() <= oidx) { total(state, Fixnum::from(oidx+1)); } return val; }
/** @todo Should we queue thread? Probably unnecessary. --rue */ void Thread::priority(STATE, Fixnum* new_priority) { /* This gets somewhat ugly to avoid existing lists. */ if(new_priority->to_native() < 0) { Exception::argument_error(state, "Thread priority must be non-negative!"); } Tuple* scheduled = state->globals.scheduled_threads.get(); std::size_t desired = new_priority->to_ulong(); std::size_t existing = scheduled->num_fields(); if(desired >= existing) { Tuple* replacement = Tuple::create(state, (desired + 1)); replacement->copy_from(state, scheduled, Fixnum::from(0), Fixnum::from(scheduled->num_fields()), Fixnum::from(0)); for(std::size_t i = existing - 1; i <= desired; ++i) { if(replacement->at(state, i)->nil_p()) { replacement->put(state, i, List::create(state)); } } state->globals.scheduled_threads.set(replacement); scheduled = replacement; } priority_ = new_priority; }
Object* Array::set(STATE, size_t idx, Object* val) { size_t tuple_size = tuple_->num_fields(); size_t oidx = idx; idx += start_->to_native(); if(idx >= tuple_size) { // Uses the same algo as 1.8 to resize the tuple size_t new_size = tuple_size / 2; if(new_size < 3) { new_size = 3; } Tuple* nt = Tuple::create(state, new_size+idx); nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0)); tuple(state, nt); start(state, Fixnum::from(0)); idx = oidx; } tuple_->put(state, idx, val); if((size_t)total_->to_native() <= oidx) { total(state, Fixnum::from(oidx+1)); } return val; }
void test_copy_from_length_exceeds_destination() { Tuple* tuple = new_tuple(); Tuple* dest = Tuple::create(state, 2); TS_ASSERT_THROWS_ASSERT(dest->copy_from(state, tuple, Fixnum::from(0), Fixnum::from(3), Fixnum::from(0)), const RubyException &e, TS_ASSERT(Exception::object_bounds_exceeded_error_p(state, e.exception))); }
void test_copy_from_other_empty() { Tuple* tuple = Tuple::create(state, 0); Tuple* dest = new_tuple(); dest->copy_from(state, tuple, Fixnum::from(0), Fixnum::from(0), Fixnum::from(0)); TS_ASSERT_EQUALS(Fixnum::from(1), as<Fixnum>(dest->at(state, 0))); TS_ASSERT_EQUALS(Fixnum::from(4), as<Fixnum>(dest->at(state, 1))); TS_ASSERT_EQUALS(Fixnum::from(9), as<Fixnum>(dest->at(state, 2))); }
void Array::unshift(STATE, Object* val) { native_int new_size = total_->to_native() + 1; native_int lend = start_->to_native(); if(lend > 0) { tuple_->put(state, lend-1, val); start(state, Fixnum::from(lend-1)); total(state, Fixnum::from(new_size)); } else { Tuple* nt = Tuple::create(state, new_size); nt->copy_from(state, tuple_, start_, total_, Fixnum::from(1)); nt->put(state, 0, val); total(state, Fixnum::from(new_size)); start(state, Fixnum::from(0)); tuple(state, nt); } }
void test_copy_from_to_empty_this() { Tuple* tuple = new_tuple(); Tuple* dest = Tuple::create(state, 0); dest->copy_from(state, tuple, Fixnum::from(0), Fixnum::from(0), Fixnum::from(0)); }