Skip to content

Commit

Permalink
Revamp FromRuby conversions by introducing RubyType class to simplify…
Browse files Browse the repository at this point in the history
…/remove code. Add support for passing Ruby arrays to pointers to fundamental types in C++.
  • Loading branch information
cfis committed Dec 22, 2024
1 parent 6e7002d commit 1d1db2a
Show file tree
Hide file tree
Showing 7 changed files with 1,022 additions and 1,274 deletions.
2 changes: 1 addition & 1 deletion rice/cpp_api/Array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ namespace Rice
//! C++ APIs that take large chunks of memory should not be passed Ruby Arrrays.
//! \return std::unique_ptr that is owned by the caller.
template<typename T>
std::unique_ptr<T[]> toPtr() const;
std::unique_ptr<T[]> pack();

private:
//! A helper class so array[index]=value can work.
Expand Down
18 changes: 5 additions & 13 deletions rice/cpp_api/Array.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,12 @@ namespace Rice
}

template<typename T>
std::unique_ptr<T[]> Array::toPtr() const
std::unique_ptr<T[]> Array::pack()
{
std::unique_ptr<T[]> result(new T[this->size()]);

auto fromRuby = detail::From_Ruby<T>();

T* current = result.get();

for (int i = 0; i<this->size(); i++)
{
*current = fromRuby.convert(this->operator[](i));
current++;
}

String string = this->call("pack", detail::RubyType<T>::packTemplate);
VALUE value = string.value();
std::unique_ptr<T[]> result = std::make_unique<T[]>(this->size());
memcpy(result.get(), RSTRING_PTR(value), RSTRING_LEN(value));
return std::move(result);
}

Expand Down
19 changes: 19 additions & 0 deletions rice/detail/RubyType.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef Rice__detail__ruby__type__hpp_
#define Rice__detail__ruby__type__hpp_

#include <set>

namespace Rice::detail
{
template <typename T>
class RubyType
{
public:
static std::set<ruby_value_type> types();
static std::set<ruby_value_type> convertibleFrom();
static T(*converter)(VALUE);
static std::string packTemplate;
};
}

#endif // Rice__detail__ruby__type__hpp_
172 changes: 172 additions & 0 deletions rice/detail/RubyType.ipp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
namespace Rice::detail
{
template<>
class RubyType<bool>
{
public:
using FromRuby_T = bool(*)(VALUE);

static inline FromRuby_T fromRuby = RB_TEST;
static inline constexpr ruby_value_type valueType = RUBY_T_TRUE;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_NIL, RUBY_T_FALSE };
static inline std::string packTemplate = "not supported";
};

template<>
class RubyType<char>
{
public:
using FromRuby_T = char(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2char_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_STRING };
static inline std::string packTemplate = CHAR_MIN < 0 ? "c*" : "C*";
};

template<>
class RubyType<signed char>
{
public:
// Hack - need to later typecast
using FromRuby_T = char(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2char_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_STRING };
static inline std::string packTemplate = "c*";
};

template<>
class RubyType<unsigned char>
{
public:
// Hack - need to later typecast, although char's in ruby are unsigned
using FromRuby_T = char(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2char_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_STRING };
static inline std::string packTemplate = "C*";
};

template<>
class RubyType<double>
{
public:
using FromRuby_T = double(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2dbl;
static inline constexpr ruby_value_type valueType = RUBY_T_FLOAT;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_FIXNUM, RUBY_T_BIGNUM };
static inline std::string packTemplate = "d*";
};

template<>
class RubyType<float>
{
public:
using FromRuby_T = double(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2dbl;
static inline constexpr ruby_value_type valueType = RUBY_T_FLOAT;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_FIXNUM, RUBY_T_BIGNUM };
static inline std::string packTemplate = "f*";
};

template<>
class RubyType<int>
{
public:
using FromRuby_T = int(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2int_inline;
static const ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "i*";
};

template<>
class RubyType<unsigned int>
{
public:
using FromRuby_T = unsigned int(*)(VALUE);

static inline FromRuby_T fromRuby = RB_NUM2UINT;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "I*";
};

template<>
class RubyType<long>
{
public:
using FromRuby_T = long(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2long_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "l_*";
};

template<>
class RubyType<unsigned long>
{
public:
using FromRuby_T = unsigned long(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2ulong_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "L_*";
};

template<>
class RubyType<long long>
{
public:
using FromRuby_T = long long(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2ll_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "q_*";
};

template<>
class RubyType<unsigned long long>
{
public:
using FromRuby_T = unsigned long long(*)(VALUE);

static inline FromRuby_T fromRuby = RB_NUM2ULL;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "Q_*";
};

template<>
class RubyType<short>
{
public:
using FromRuby_T = short(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2short_inline;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "s*";
};

template<>
class RubyType<unsigned short>
{
public:
using FromRuby_T = unsigned short(*)(VALUE);

static inline FromRuby_T fromRuby = rb_num2ushort;
static inline constexpr ruby_value_type valueType = RUBY_T_FIXNUM;
static inline std::set<ruby_value_type> castableTypes = { RUBY_T_BIGNUM, RUBY_T_FLOAT };
static inline std::string packTemplate = "S*";
};
}
Loading

0 comments on commit 1d1db2a

Please sign in to comment.