void test_collect_young_copies_chararray_bodies() { ObjectMemory& om = *state->vm()->om; CharArray* obj; obj = CharArray::create(state, 3); obj->raw_bytes()[0] = 48; Root r(roots, obj); om.collect_young(*gc_data); obj = (CharArray*)roots->front()->get(); TS_ASSERT_EQUALS(obj->raw_bytes()[0], static_cast<char>(48)); }
String* String::resize_capacity(STATE, Fixnum* count) { native_int sz = count->to_native(); if(sz < 0) { Exception::argument_error(state, "negative byte array size"); } else if(sz >= INT32_MAX) { // >= is used deliberately because we use a size of + 1 // for the byte array Exception::argument_error(state, "too large byte array size"); } CharArray* ba = CharArray::create(state, sz + 1); native_int copy_size = sz; native_int data_size = as<CharArray>(data_)->size(); // Check that we don't copy any data outside the existing byte array if(unlikely(copy_size > data_size)) { copy_size = data_size; } memcpy(ba->raw_bytes(), byte_address(), copy_size); // We've unshared shared(state, Qfalse); data(state, ba); hash_value(state, nil<Fixnum>()); // If we shrunk it and num_bytes said there was more than there // is, clamp it. if(num_bytes()->to_native() > sz) { num_bytes(state, count); } return this; }
/* We use the garbage collector's feature to "pin" an Object at a * particular memory location to allow C code to write directly into the * contets of a Ruby String (actually, a CharArray, which provides the * storage for String). Since any method on String that mutates self may * cause a new CharArray to be created, we always check whether the * String is pinned and update the RString structure unconditionally. */ void ensure_pinned(NativeMethodEnvironment* env, String* string, RString* rstring) { CharArray* ca = string->data(); size_t byte_size = ca->size(); if(!ca->pinned_p()) { ca = CharArray::create_pinned(env->state(), byte_size); memcpy(ca->raw_bytes(), string->byte_address(), byte_size); string->data(env->state(), ca); } char* ptr = reinterpret_cast<char*>(ca->raw_bytes()); ptr[byte_size-1] = 0; rstring->dmwmb = rstring->ptr = ptr; rstring->len = string->size(); rstring->aux.capa = byte_size; rstring->aux.shared = Qfalse; }
String* String::create_reserved(STATE, native_int bytes) { String *so; so = state->new_object<String>(G(string)); so->num_bytes(state, Fixnum::from(0)); so->hash_value(state, nil<Fixnum>()); so->shared(state, Qfalse); CharArray* ba = CharArray::create(state, bytes+1); ba->raw_bytes()[bytes] = 0; so->data(state, ba); return so; }
/* * Creates a String instance with +num_bytes+ bytes of storage. * It also pins the CharArray used for storage, so it can be passed * to an external function (like ::read) */ String* String::create_pinned(STATE, Fixnum* size) { String *so; so = state->new_object<String>(G(string)); so->num_bytes(state, size); so->hash_value(state, nil<Fixnum>()); so->shared(state, Qfalse); native_int bytes = size->to_native() + 1; CharArray* ba = CharArray::create_pinned(state, bytes); ba->raw_bytes()[bytes-1] = 0; so->data(state, ba); return so; }
String* String::append(STATE, const char* other, native_int length) { native_int current_size = size(); native_int data_size = as<CharArray>(data_)->size(); // Clamp the string size the maximum underlying byte array size if(unlikely(current_size > data_size)) { current_size = data_size; } native_int new_size = current_size + length; native_int capacity = data_size; if(capacity < new_size + 1) { // capacity needs one extra byte of room for the trailing null do { // @todo growth should be more intelligent than doubling capacity *= 2; } while(capacity < new_size + 1); // No need to call unshare and duplicate a CharArray // just to throw it away. if(shared_ == Qtrue) shared(state, Qfalse); CharArray* ba = CharArray::create(state, capacity); memcpy(ba->raw_bytes(), byte_address(), current_size); data(state, ba); } else { if(shared_ == Qtrue) unshare(state); } // Append on top of the null byte at the end of s1, not after it memcpy(byte_address() + current_size, other, length); // The 0-based index of the last character is new_size - 1 byte_address()[new_size] = 0; num_bytes(state, Fixnum::from(new_size)); hash_value(state, nil<Fixnum>()); return this; }
VALUE rb_str_resize(VALUE self, size_t len) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); String* string = capi_get_string(env, self); size_t size = as<CharArray>(string->data())->size(); if(size != len) { if(size < len) { CharArray* ca = CharArray::create_pinned(env->state(), len+1); memcpy(ca->raw_bytes(), string->byte_address(), size); string->data(env->state(), ca); } string->byte_address()[len] = 0; string->num_bytes(env->state(), Fixnum::from(len)); string->hash_value(env->state(), reinterpret_cast<Fixnum*>(RBX_Qnil)); } capi_update_string(env, self); return self; }
void test_move_bytes() { String* s = String::create(state, "xyzzy"); CharArray* c = s->data(); c->move_bytes(state, Fixnum::from(0), Fixnum::from(2), Fixnum::from(3)); TS_ASSERT_SAME_DATA(c->raw_bytes(), "xyzxy", 5); }
void test_fetch_bytes() { String* s = String::create(state, "xyzzy"); CharArray* c = s->data(); CharArray* ca = c->fetch_bytes(state, Fixnum::from(1), Fixnum::from(3)); TS_ASSERT_SAME_DATA(ca->raw_bytes(), "yzz", 3); }