Skip to content

Commit

Permalink
Improve smart pointer support including std::shared_ptr<void>
Browse files Browse the repository at this point in the history
  • Loading branch information
cfis committed Dec 2, 2024
1 parent a337258 commit 2d3b70c
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 30 deletions.
9 changes: 9 additions & 0 deletions rice/detail/TypeRegistry.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ namespace Rice::detail
return iter != registry_.end();
}

// Special case void. See comment for add above.
template <>
inline bool TypeRegistry::isDefined<void>()
{
std::type_index key(typeid(void*));
auto iter = registry_.find(key);
return iter != registry_.end();
}

template <typename T>
inline bool TypeRegistry::verify()
{
Expand Down
120 changes: 96 additions & 24 deletions rice/stl/smart_ptr.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ namespace Rice::detail
class To_Ruby<std::unique_ptr<T>>
{
public:
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;

VALUE convert(std::unique_ptr<T>& data)
{
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);

// Use custom wrapper type
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
}
};
Expand All @@ -50,22 +49,32 @@ namespace Rice::detail
class To_Ruby<std::unique_ptr<T>&>
{
public:
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;

VALUE convert(std::unique_ptr<T>& data)
{
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);

// Use custom wrapper type
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
}
};

template <typename T>
class From_Ruby<std::unique_ptr<T>&>
class From_Ruby<std::unique_ptr<T>>
{
public:
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;

Wrapper_T* is_same_smart_ptr(VALUE value)
{
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
return dynamic_cast<Wrapper_T*>(wrapper);
}

Convertible is_convertible(VALUE value)
{
if (!is_same_smart_ptr(value))
return Convertible::None;

switch (rb_type(value))
{
case RUBY_T_DATA:
Expand All @@ -76,12 +85,48 @@ namespace Rice::detail
}
}

std::unique_ptr<T>& convert(VALUE value)
std::unique_ptr<T> convert(VALUE value)
{
Wrapper_T* smartWrapper = is_same_smart_ptr(value);
if (!smartWrapper)
{
std::string message = "Invalid smart pointer wrapper";
throw std::runtime_error(message.c_str());
}
return std::move(smartWrapper->data());
}
};

template <typename T>
class From_Ruby<std::unique_ptr<T>&>
{
public:
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;

Wrapper_T* is_same_smart_ptr(VALUE value)
{
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
return dynamic_cast<Wrapper_T*>(wrapper);
}

using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
Convertible is_convertible(VALUE value)
{
if (!is_same_smart_ptr(value))
return Convertible::None;

switch (rb_type(value))
{
case RUBY_T_DATA:
return Convertible::Exact;
break;
default:
return Convertible::None;
}
}

std::unique_ptr<T>& convert(VALUE value)
{
Wrapper_T* smartWrapper = is_same_smart_ptr(value);
if (!smartWrapper)
{
std::string message = "Invalid smart pointer wrapper";
Expand All @@ -105,28 +150,51 @@ namespace Rice::detail
class To_Ruby<std::shared_ptr<T>>
{
public:
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;

VALUE convert(std::shared_ptr<T>& data)
{
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);

// Use custom wrapper type
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
}
};

template <>
class To_Ruby<std::shared_ptr<void>>
{
public:
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, void>;

VALUE convert(std::shared_ptr<void>& data)
{
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(data.get());
return detail::wrap<std::shared_ptr<void>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
}
};

template <typename T>
class From_Ruby<std::shared_ptr<T>>
{
public:
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;

From_Ruby() = default;

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

Wrapper_T* is_same_smart_ptr(VALUE value)
{
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
return dynamic_cast<Wrapper_T*>(wrapper);
}

Convertible is_convertible(VALUE value)
{
if (!is_same_smart_ptr(value))
return Convertible::None;

switch (rb_type(value))
{
case RUBY_T_DATA:
Expand All @@ -143,10 +211,7 @@ namespace Rice::detail
return this->arg_->template defaultValue<std::shared_ptr<T>>();
}

Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());

using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
Wrapper_T* smartWrapper = is_same_smart_ptr(value);
if (!smartWrapper)
{
std::string message = "Invalid smart pointer wrapper";
Expand All @@ -162,12 +227,11 @@ namespace Rice::detail
class To_Ruby<std::shared_ptr<T>&>
{
public:
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;

VALUE convert(std::shared_ptr<T>& data)
{
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);

// Use custom wrapper type
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
}
};
Expand All @@ -176,14 +240,25 @@ namespace Rice::detail
class From_Ruby<std::shared_ptr<T>&>
{
public:
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;

From_Ruby() = default;

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

Wrapper_T* is_same_smart_ptr(VALUE value)
{
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
return dynamic_cast<Wrapper_T*>(wrapper);
}

Convertible is_convertible(VALUE value)
{
if (!is_same_smart_ptr(value))
return Convertible::None;

switch (rb_type(value))
{
case RUBY_T_DATA:
Expand All @@ -200,10 +275,7 @@ namespace Rice::detail
return this->arg_->template defaultValue<std::shared_ptr<T>>();
}

Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());

using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
Wrapper_T* smartWrapper = is_same_smart_ptr(value);
if (!smartWrapper)
{
std::string message = "Invalid smart pointer wrapper";
Expand Down
2 changes: 0 additions & 2 deletions test/embed_ruby.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ void embed_ruby()
ruby_init();
ruby_init_loadpath();

#if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 3
// Force the prelude / builtins
const char* opts[] = { "ruby", "-e;" };
ruby_options(2, (char**)opts);
#endif

initialized__ = true;
}
Expand Down
Loading

0 comments on commit 2d3b70c

Please sign in to comment.