Exemple #1
0
  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));
  }
Exemple #2
0
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;
}
Exemple #3
0
    /* 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;
    }
Exemple #4
0
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;
}
Exemple #5
0
/*
 * 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;
}
Exemple #6
0
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;
}
Exemple #7
0
  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);
 }