00001 #include "typelib.hh"
00002 #include <iostream>
00003
00004 #include <boost/bind.hpp>
00005 #include <typelib/value_ops.hh>
00006
00007 using namespace Typelib;
00008 using std::vector;
00009 using namespace typelib_ruby;
00010
00011
00012
00013
00014
00015 static VALUE compound_get_fields(VALUE self)
00016 {
00017 if (self == cCompound)
00018 return rb_ary_new();
00019
00020 Type const& type(rb2cxx::object<Type>(self));
00021 Compound const& compound(dynamic_cast<Compound const&>(type));
00022 Compound::FieldList const& fields(compound.getFields());
00023 Compound::FieldList::const_iterator it, end = fields.end();
00024
00025 VALUE registry = type_get_registry(self);
00026 VALUE fieldlist = rb_ary_new();
00027 for (it = fields.begin(); it != end; ++it)
00028 {
00029 VALUE field_name = rb_str_new2(it->getName().c_str());
00030 VALUE field_type = cxx2rb::type_wrap(it->getType(), registry);
00031
00032 VALUE field_def = rb_ary_new2(3);
00033 rb_ary_store(field_def, 0, field_name);
00034 rb_ary_store(field_def, 1, INT2FIX(it->getOffset()));
00035 rb_ary_store(field_def, 2, field_type);
00036 rb_ary_push(fieldlist, field_def);
00037 }
00038
00039 return fieldlist;
00040 }
00041
00042
00043 static VALUE compound_field_get(VALUE rbvalue, VALUE name, VALUE raw)
00044 {
00045 VALUE registry = value_get_registry(rbvalue);
00046 Value value = rb2cxx::object<Value>(rbvalue);
00047 if (! value.getData())
00048 return Qnil;
00049
00050 try {
00051 Value field_value = value_get_field(value, StringValuePtr(name));
00052 if (RTEST(raw))
00053 return cxx2rb::value_wrap(field_value, registry, rbvalue);
00054 else return typelib_to_ruby(field_value, registry, rbvalue);
00055 }
00056 catch(FieldNotFound)
00057 { rb_raise(rb_eArgError, "no field '%s'", StringValuePtr(name)); }
00058 catch(std::exception const& e)
00059 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00060 }
00061
00062 static VALUE compound_field_set(VALUE self, VALUE name, VALUE newval)
00063 {
00064 Value& tlib_value(rb2cxx::object<Value>(self));
00065
00066 try {
00067 Value field_value = value_get_field(tlib_value, StringValuePtr(name));
00068 typelib_from_ruby(field_value, newval);
00069 return newval;
00070 }
00071 catch(FieldNotFound)
00072 { rb_raise(rb_eArgError, "no field '%s' in '%s'", StringValuePtr(name), rb_obj_classname(self)); }
00073 catch(std::exception const& e)
00074 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00075 }
00076
00077
00078
00079
00080
00081
00082 static VALUE pointer_deference(VALUE self)
00083 {
00084 VALUE pointed_to = rb_iv_get(self, "@points_to");
00085 if (!NIL_P(pointed_to))
00086 return pointed_to;
00087
00088 Value const& value(rb2cxx::object<Value>(self));
00089 Indirect const& indirect(static_cast<Indirect const&>(value.getType()));
00090
00091 VALUE registry = value_get_registry(self);
00092
00093 void* ptr_value = *reinterpret_cast<void**>(value.getData());
00094 if (!ptr_value)
00095 rb_raise(rb_eArgError, "cannot deference a NULL pointer");
00096
00097 Value new_value(ptr_value, indirect.getIndirection() );
00098 return cxx2rb::value_wrap(new_value, registry, Qnil);
00099 }
00100
00101
00102
00103
00104
00105 Enum::integral_type rb2cxx::enum_value(VALUE rb_value, Enum const& e)
00106 {
00107
00108 if (TYPE(rb_value) == T_FIXNUM)
00109 {
00110 Enum::integral_type value = FIX2INT(rb_value);
00111 try {
00112 e.get(value);
00113 return value;
00114 }
00115 catch(Enum::ValueNotFound) { }
00116 rb_raise(rb_eArgError, "%i is not a valid value for %s", value, e.getName().c_str());
00117 }
00118
00119 char const* name;
00120 if (SYMBOL_P(rb_value))
00121 name = rb_id2name(SYM2ID(rb_value));
00122 else
00123 name = StringValuePtr(rb_value);
00124
00125 try { return e.get(name); }
00126 catch(Enum::SymbolNotFound) { }
00127 rb_raise(rb_eArgError, "%s is not a valid symbol for %s", name, e.getName().c_str());
00128 }
00129
00130
00131
00132
00133
00134
00135 VALUE enum_keys(VALUE self)
00136 {
00137 if (self == cEnum)
00138 return rb_hash_new();
00139
00140 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00141
00142 VALUE keys = rb_iv_get(self, "@values");
00143 if (!NIL_P(keys))
00144 return keys;
00145
00146 keys = rb_hash_new();
00147 typedef std::list<std::string> string_list;
00148 string_list names = type.names();
00149 for (string_list::const_iterator it = names.begin(); it != names.end(); ++it)
00150 rb_hash_aset(keys, rb_str_new2(it->c_str()), INT2FIX(type.get(*it)));
00151
00152 rb_iv_set(self, "@values", keys);
00153 return keys;
00154 }
00155
00156
00157
00158
00159
00160
00161 static VALUE enum_value_of(VALUE self, VALUE name)
00162 {
00163 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00164
00165 try {
00166 int value = type.get(StringValuePtr(name));
00167 return INT2NUM(value);
00168 } catch (Enum::SymbolNotFound) {
00169 rb_raise(rb_eArgError, "this enumeration has no value for %s", StringValuePtr(name));
00170 }
00171 }
00172
00173
00174
00175
00176
00177
00178
00179 static VALUE enum_name_of(VALUE self, VALUE integer)
00180 {
00181 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00182
00183 try {
00184 std::string name = type.get(NUM2INT(integer));
00185 return rb_str_new2(name.c_str());
00186 } catch (Enum::ValueNotFound) {
00187 rb_raise(rb_eArgError, "this enumeration has no name for %i", NUM2INT(integer));
00188 }
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 static VALUE indirect_type_deference(VALUE self)
00201 {
00202 VALUE registry = type_get_registry(self);
00203 Type const& type(rb2cxx::object<Type>(self));
00204 Indirect const& indirect(static_cast<Indirect const&>(type));
00205 return cxx2rb::type_wrap(indirect.getIndirection(), registry);
00206 }
00207
00208
00209 static Value array_element(VALUE rbarray, VALUE rbindex)
00210 {
00211 Value& value(rb2cxx::object<Value>(rbarray));
00212 Array const& array(static_cast<Array const&>(value.getType()));
00213 size_t index = NUM2INT(rbindex);
00214
00215 if (index >= array.getDimension())
00216 {
00217 rb_raise(rb_eIndexError, "Out of bounds: %lu > %lu", index, array.getDimension());
00218 return Value();
00219 }
00220
00221 Type const& array_type(array.getIndirection());
00222
00223 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00224 data += array_type.getSize() * index;
00225 return Value(data, array_type);
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235 static VALUE array_get(int argc, VALUE* argv, VALUE self)
00236 {
00237 Value& value = rb2cxx::object<Value>(self);
00238 Array const& array = static_cast<Array const&>(value.getType());
00239 if (array.getDimension() == 0)
00240 return self;
00241
00242 Type const& array_type = array.getIndirection();
00243 VALUE registry = value_get_registry(self);
00244
00245 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00246 size_t index = NUM2INT(argv[0]);
00247 if (index >= array.getDimension())
00248 rb_raise(rb_eIndexError, "Out of bounds: %li > %li", index, array.getDimension());
00249
00250 if (argc == 1)
00251 {
00252 Value v = Value(data + array_type.getSize() * index, array_type);
00253 return cxx2rb::value_wrap( v, registry, self );
00254 }
00255 else if (argc == 2)
00256 {
00257 VALUE ret = rb_ary_new();
00258 size_t size = NUM2INT(argv[1]);
00259 if (index + size > array.getDimension())
00260 rb_raise(rb_eIndexError, "Out of bounds: %li > %li", index + size - 1, array.getDimension());
00261
00262 for (size_t i = index; i < index + size; ++i)
00263 {
00264 Value v = Value(data + array_type.getSize() * i, array_type);
00265 VALUE rb_v = cxx2rb::value_wrap( v, registry, self );
00266
00267 rb_ary_push(ret, rb_v);
00268 }
00269
00270 return ret;
00271 }
00272 else
00273 rb_raise(rb_eArgError, "invalid argument count (%i for 1 or 2)", argc);
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283 static VALUE array_set(VALUE self, VALUE rbindex, VALUE newvalue)
00284 {
00285 Value element = array_element(self, rbindex);
00286 return typelib_from_ruby(element, newvalue);
00287 }
00288
00289
00290
00291
00292
00293
00294 static VALUE array_do_each(VALUE rbarray)
00295 {
00296 Value& value = rb2cxx::object<Value>(rbarray);
00297 Array const& array = static_cast<Array const&>(value.getType());
00298 if (array.getDimension() == 0)
00299 return rbarray;
00300
00301 Type const& array_type = array.getIndirection();
00302 VALUE registry = value_get_registry(rbarray);
00303
00304 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00305
00306 for (size_t i = 0; i < array.getDimension(); ++i, data += array_type.getSize())
00307 rb_yield(cxx2rb::value_wrap( Value(data, array_type), registry, rbarray ));
00308
00309 return rbarray;
00310 }
00311
00312
00313
00314
00315
00316
00317 static VALUE array_size(VALUE rbarray)
00318 {
00319 Value& value(rb2cxx::object<Value>(rbarray));
00320 Array const& array(static_cast<Array const&>(value.getType()));
00321 return INT2FIX(array.getDimension());
00322 }
00323
00324
00325
00326
00327
00328
00329 static VALUE array_class_length(VALUE rbarray)
00330 {
00331 Array const& array(dynamic_cast<Array const&>(rb2cxx::object<Type>(rbarray)));
00332 return INT2FIX(array.getDimension());
00333 }
00334
00335
00336
00337
00338
00339
00340
00341 static VALUE pointer_nil_p(VALUE self)
00342 {
00343 Value const& value(rb2cxx::object<Value>(self));
00344 if ( *reinterpret_cast<void**>(value.getData()) == 0 )
00345 return Qtrue;
00346 return Qfalse;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 static VALUE numeric_type_integer_p(VALUE self)
00356 {
00357 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00358 return type.getNumericCategory() == Numeric::Float ? Qfalse : Qtrue;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 static VALUE numeric_type_size(VALUE self)
00368 {
00369 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00370 return INT2FIX(type.getSize());
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380 static VALUE numeric_type_unsigned_p(VALUE self)
00381 {
00382 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00383 switch(type.getNumericCategory())
00384 {
00385 case Numeric::SInt: return Qfalse;
00386 case Numeric::UInt: return Qtrue;
00387 case Numeric::Float:
00388 rb_raise(rb_eArgError, "not an integral type");
00389 }
00390 return Qnil;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 static VALUE container_kind(VALUE self)
00402 {
00403 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00404 return rb_str_new2(type.kind().c_str());
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 static VALUE container_natural_size(VALUE self)
00416 {
00417 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00418 return INT2FIX(type.getNaturalSize());
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 static VALUE container_random_access_p(VALUE self)
00428 {
00429 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00430 return type.isRandomAccess() ? Qtrue : Qfalse;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440 static VALUE container_length(VALUE self)
00441 {
00442 Value value = rb2cxx::object<Value>(self);
00443 Container const& type(dynamic_cast<Container const&>(value.getType()));
00444
00445 return INT2NUM(type.getElementCount(value.getData()));
00446 }
00447
00448
00449
00450
00451
00452
00453
00454 static VALUE container_clear(VALUE self)
00455 {
00456 Value value = rb2cxx::object<Value>(self);
00457 Container const& type(dynamic_cast<Container const&>(value.getType()));
00458
00459 type.clear(value.getData());
00460 return Qnil;
00461 }
00462
00463 static Typelib::Value container_element(uint64_t* buffer10, Type const& element_t, VALUE obj)
00464 {
00465 Typelib::Value element_v;
00466 if (element_t.getCategory() == Type::Numeric && sizeof(int64_t) * 10 >= element_t.getSize())
00467 {
00468
00469
00470 element_v = Value(buffer10, element_t);
00471 typelib_from_ruby(element_v, obj);
00472 }
00473 else
00474 {
00475 element_v = rb2cxx::object<Value>(obj);
00476 if (element_t != element_v.getType())
00477 rb_raise(rb_eArgError, "wrong type %s for new element, expected %s", element_v.getType().getName().c_str(), element_t.getName().c_str());
00478 }
00479 return element_v;
00480 }
00481
00482 static VALUE container_do_push(VALUE self, VALUE obj)
00483 {
00484 Value container_v = rb2cxx::object<Value>(self);
00485 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00486
00487 uint64_t buffer[10];
00488 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00489 container_t.push(container_v.getData(), element_v);
00490 return self;
00491 }
00492
00493 static VALUE container_do_set(VALUE self, VALUE index, VALUE obj)
00494 {
00495 Value container_v = rb2cxx::object<Value>(self);
00496 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00497
00498 uint64_t buffer[10];
00499 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00500 container_t.setElement(container_v.getData(), NUM2INT(index), element_v);
00501 return self;
00502 }
00503
00504 static VALUE container_do_get(VALUE self, VALUE index, VALUE raw)
00505 {
00506 Value container_v = rb2cxx::object<Value>(self);
00507 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00508 VALUE registry = value_get_registry(self);
00509
00510 Value v = container_t.getElement(container_v.getData(), NUM2INT(index));
00511 if (RTEST(raw))
00512 return cxx2rb::value_wrap(v, registry, self);
00513 else return typelib_to_ruby(v, registry, self);
00514 }
00515
00516 struct ContainerIterator : public ValueVisitor
00517 {
00518 VALUE m_registry;
00519 VALUE m_parent;
00520 bool m_raw;
00521
00522 ContainerIterator(VALUE registry, VALUE parent, bool raw)
00523 {
00524 m_registry = registry;
00525 m_parent = parent;
00526 m_raw = raw;
00527 }
00528 virtual void dispatch(Value v)
00529 {
00530 if (m_raw)
00531 rb_yield(cxx2rb::value_wrap(v, m_registry, m_parent));
00532 else
00533 rb_yield(typelib_to_ruby(v, m_registry, m_parent));
00534 }
00535 };
00536
00537
00538
00539
00540
00541
00542
00543 static VALUE container_each(VALUE self, VALUE raw)
00544 {
00545 Value value = rb2cxx::object<Value>(self);
00546 VALUE registry = value_get_registry(self);
00547 ContainerIterator iterator(registry, self, RTEST(raw));
00548 dynamic_cast<Typelib::Container const&>(value.getType()).visit(value.getData(), iterator);
00549 return self;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 static VALUE container_erase(VALUE self, VALUE obj)
00560 {
00561 Value container_v = rb2cxx::object<Value>(self);
00562 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00563
00564 uint64_t buffer[10];
00565 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00566
00567 if (container_t.erase(container_v.getData(), element_v))
00568 return Qtrue;
00569 else
00570 return Qfalse;
00571 }
00572
00573 bool container_delete_if_i(Value v, VALUE registry, VALUE container)
00574 {
00575 VALUE rb_v = cxx2rb::value_wrap(v, registry, container);
00576 if (RTEST(rb_yield(rb_v)))
00577 return true;
00578 return false;
00579 }
00580
00581
00582
00583
00584
00585
00586
00587 static VALUE container_delete_if(VALUE self)
00588 {
00589 Value container_v = rb2cxx::object<Value>(self);
00590 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00591
00592 VALUE registry = value_get_registry(self);
00593 container_t.delete_if(container_v.getData(), boost::bind(container_delete_if_i, _1, registry, self));
00594 return self;
00595 }
00596
00597
00598
00599
00600
00601
00602
00603 static VALUE vector_contained_memory_id(VALUE self)
00604 {
00605 Value container_v = rb2cxx::object<Value>(self);
00606 std::vector<uint8_t> const* vector = reinterpret_cast<std::vector<uint8_t>*>(container_v.getData());
00607 if (vector->empty())
00608 return Qnil;
00609 return ULL2NUM(reinterpret_cast<uint64_t>(&(*vector)[0]));
00610 }
00611
00612
00613
00614
00615
00616
00617
00618
00619 static VALUE numeric_to_ruby(VALUE mod, VALUE self)
00620 {
00621 Value const& value(rb2cxx::object<Value>(self));
00622 VALUE registry = value_get_registry(self);
00623 try {
00624 return typelib_to_ruby(value, registry, Qnil);
00625 } catch(Typelib::NullTypeFound) { }
00626 rb_raise(rb_eTypeError, "trying to convert 'void'");
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 static VALUE numeric_from_ruby(VALUE self, VALUE arg)
00639 {
00640 Value& value(rb2cxx::object<Value>(self));
00641 try {
00642 typelib_from_ruby(value, arg);
00643 return self;
00644 } catch(Typelib::UnsupportedType) { }
00645 rb_raise(rb_eTypeError, "cannot perform the requested convertion");
00646 }
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 void typelib_ruby::Typelib_init_specialized_types()
00674 {
00675 VALUE mTypelib = rb_define_module("Typelib");
00676 cNumeric = rb_define_class_under(mTypelib, "NumericType", cType);
00677 rb_define_singleton_method(cNumeric, "integer?", RUBY_METHOD_FUNC(numeric_type_integer_p), 0);
00678 rb_define_singleton_method(cNumeric, "unsigned?", RUBY_METHOD_FUNC(numeric_type_unsigned_p), 0);
00679 rb_define_singleton_method(cNumeric, "size", RUBY_METHOD_FUNC(numeric_type_size), 0);
00680 rb_define_singleton_method(cNumeric, "to_ruby", RUBY_METHOD_FUNC(&numeric_to_ruby), 1);
00681 rb_define_method(cNumeric, "typelib_from_ruby", RUBY_METHOD_FUNC(&numeric_from_ruby), 1);
00682
00683 cOpaque = rb_define_class_under(mTypelib, "OpaqueType", cType);
00684 cNull = rb_define_class_under(mTypelib, "NullType", cType);
00685
00686 cIndirect = rb_define_class_under(mTypelib, "IndirectType", cType);
00687 rb_define_singleton_method(cIndirect, "deference", RUBY_METHOD_FUNC(indirect_type_deference), 0);
00688
00689 cPointer = rb_define_class_under(mTypelib, "PointerType", cIndirect);
00690 rb_define_method(cPointer, "deference", RUBY_METHOD_FUNC(pointer_deference), 0);
00691 rb_define_method(cPointer, "null?", RUBY_METHOD_FUNC(pointer_nil_p), 0);
00692
00693 cCompound = rb_define_class_under(mTypelib, "CompoundType", cType);
00694 rb_define_singleton_method(cCompound, "get_fields", RUBY_METHOD_FUNC(compound_get_fields), 0);
00695 rb_define_method(cCompound, "typelib_get_field", RUBY_METHOD_FUNC(compound_field_get), 2);
00696 rb_define_method(cCompound, "typelib_set_field", RUBY_METHOD_FUNC(compound_field_set), 2);
00697
00698 cEnum = rb_define_class_under(mTypelib, "EnumType", cType);
00699 rb_define_singleton_method(cEnum, "keys", RUBY_METHOD_FUNC(enum_keys), 0);
00700 rb_define_singleton_method(cEnum, "value_of", RUBY_METHOD_FUNC(enum_value_of), 1);
00701 rb_define_singleton_method(cEnum, "name_of", RUBY_METHOD_FUNC(enum_name_of), 1);
00702 rb_define_singleton_method(cEnum, "to_ruby", RUBY_METHOD_FUNC(&numeric_to_ruby), 1);
00703 rb_define_method(cEnum, "typelib_from_ruby", RUBY_METHOD_FUNC(&numeric_from_ruby), 1);
00704
00705 cArray = rb_define_class_under(mTypelib, "ArrayType", cIndirect);
00706 rb_define_singleton_method(cArray, "length", RUBY_METHOD_FUNC(array_class_length), 0);
00707 rb_define_method(cArray, "do_get", RUBY_METHOD_FUNC(array_get), -1);
00708 rb_define_method(cArray, "do_set", RUBY_METHOD_FUNC(array_set), 2);
00709 rb_define_method(cArray, "do_each", RUBY_METHOD_FUNC(array_do_each), 0);
00710 rb_define_method(cArray, "size", RUBY_METHOD_FUNC(array_size), 0);
00711
00712 cContainer = rb_define_class_under(mTypelib, "ContainerType", cIndirect);
00713 rb_define_singleton_method(cContainer, "container_kind", RUBY_METHOD_FUNC(container_kind), 0);
00714 rb_define_singleton_method(cContainer, "natural_size", RUBY_METHOD_FUNC(container_natural_size), 0);
00715 rb_define_singleton_method(cContainer, "random_access?", RUBY_METHOD_FUNC(container_random_access_p), 0);
00716 rb_define_method(cContainer, "length", RUBY_METHOD_FUNC(container_length), 0);
00717 rb_define_method(cContainer, "size", RUBY_METHOD_FUNC(container_length), 0);
00718 rb_define_method(cContainer, "do_clear", RUBY_METHOD_FUNC(container_clear), 0);
00719 rb_define_method(cContainer, "do_push", RUBY_METHOD_FUNC(container_do_push), 1);
00720 rb_define_method(cContainer, "do_get", RUBY_METHOD_FUNC(container_do_get), 2);
00721 rb_define_method(cContainer, "do_set", RUBY_METHOD_FUNC(container_do_set), 2);
00722 rb_define_method(cContainer, "do_each", RUBY_METHOD_FUNC(container_each), 1);
00723 rb_define_method(cContainer, "do_erase", RUBY_METHOD_FUNC(container_erase), 1);
00724 rb_define_method(cContainer, "do_delete_if", RUBY_METHOD_FUNC(container_delete_if), 0);
00725
00726 VALUE mVector = rb_define_module_under(cContainer, "StdVector");
00727 rb_define_method(mVector, "contained_memory_id", RUBY_METHOD_FUNC(vector_contained_memory_id), 0);
00728 }
00729