Skip to content

Commit

Permalink
Support pointers in STL collections like vectors. Fixes #192.
Browse files Browse the repository at this point in the history
  • Loading branch information
cfis committed Feb 17, 2024
1 parent ed3f5c4 commit 8e3d93f
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 21 deletions.
27 changes: 27 additions & 0 deletions rice/Data_Object.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,33 @@ namespace Rice::detail
}
};

template<typename T>
class From_Ruby<T*&>
{
static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
"Data_Object cannot be used with fundamental types");
public:
bool is_convertible(VALUE value)
{
return rb_type(value) == RUBY_T_DATA &&
Data_Type<T>::is_descendant(value);
}

T* convert(VALUE value)
{
using Intrinsic_T = intrinsic_type<T>;

if (value == Qnil)
{
return nullptr;
}
else
{
return Data_Object<Intrinsic_T>::from_ruby(value);
}
}
};

template<typename T>
class From_Ruby<Data_Object<T>>
{
Expand Down
2 changes: 1 addition & 1 deletion rice/stl/optional.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Rice::detail
{
constexpr static bool verify()
{
return Type<T>::verify();
return Type<intrinsic_type<T>>::verify();
}
};

Expand Down
58 changes: 39 additions & 19 deletions rice/stl/string.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,40 @@ namespace Rice::detail
Arg* arg_ = nullptr;
};

template<>
class From_Ruby<std::string&>
{
public:
From_Ruby() = default;

explicit From_Ruby(Arg* arg) : arg_(arg)
{
}

bool is_convertible(VALUE value)
{
return rb_type(value) == RUBY_T_STRING;
}

std::string& convert(VALUE value)
{
if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
{
return this->arg_->defaultValue<std::string>();
}
else
{
detail::protect(rb_check_type, value, (int)T_STRING);
this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
return this->converted_;
}
}

private:
Arg* arg_ = nullptr;
std::string converted_;
};

template<>
class From_Ruby<std::string*>
{
Expand All @@ -88,36 +122,22 @@ namespace Rice::detail
};

template<>
class From_Ruby<std::string&>
class From_Ruby<std::string*&>
{
public:
From_Ruby() = default;

explicit From_Ruby(Arg* arg) : arg_(arg)
{
}

bool is_convertible(VALUE value)
{
return rb_type(value) == RUBY_T_STRING;
}

std::string& convert(VALUE value)
std::string* convert(VALUE value)
{
if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
{
return this->arg_->defaultValue<std::string>();
}
else
{
detail::protect(rb_check_type, value, (int)T_STRING);
this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
return this->converted_;
}
detail::protect(rb_check_type, value, (int)T_STRING);
this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
return &this->converted_;
}

private:
Arg* arg_ = nullptr;
std::string converted_;
};
}
2 changes: 1 addition & 1 deletion rice/stl/vector.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ namespace Rice
{
static bool verify()
{
Type<T>::verify();
Type<intrinsic_type<T>>::verify();

if (!detail::Registries::instance.types.isDefined<std::vector<T>>())
{
Expand Down
60 changes: 60 additions & 0 deletions test/test_Stl_Vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,3 +809,63 @@ TESTCASE(ToEnumSize)

ASSERT_EQUAL(3, detail::From_Ruby<int>().convert(result));
}

namespace
{
std::vector<std::string*> vectorOfStringPointers()
{
std::vector<std::string*> result;
std::string* pString = new std::string("Hello");
result.push_back(pString);
return result;
}
}

TESTCASE(StringPointerVector)
{
define_global_function("vector_of_string_pointers", &vectorOfStringPointers);

Module m(rb_mKernel);
Data_Object<std::vector<std::string*>> vec = m.call("vector_of_string_pointers");
ASSERT_EQUAL(1, vec->size());

std::string expected("Hello");
std::string* actual = (*vec)[0];
ASSERT_EQUAL(expected, *actual);
}

namespace
{
class MyClass2
{
public:
MyClass2(std::string name): name(name)
{
}
std::string name;
};

std::vector<MyClass2*> vectorOfMyClass2Pointers()
{
std::vector<MyClass2*> result;
MyClass2* pMyClass = new MyClass2("Hello MyClass2");
result.push_back(pMyClass);
return result;
}
}

TESTCASE(MyClass2PointerVector)
{
Class c = define_class<MyClass2>("MyClass2").
define_constructor(Constructor<MyClass2, std::string>()).
define_attr("name", &MyClass2::name, AttrAccess::Read);

define_global_function("vector_of_myclass2_pointers", &vectorOfMyClass2Pointers);

Module m(rb_mKernel);
Data_Object<std::vector<MyClass2*>> result = m.call("vector_of_myclass2_pointers");
ASSERT_EQUAL(1, result->size());

MyClass2* pMyClass = (*result)[0];
ASSERT_EQUAL("Hello MyClass2", pMyClass->name);
}

0 comments on commit 8e3d93f

Please sign in to comment.