rice/detail/NativeIterator.ipp in rice-4.3.0 vs rice/detail/NativeIterator.ipp in rice-4.3.1

- old
+ new

@@ -1,102 +1,102 @@ -#include <iterator> -#include <functional> -#include <type_traits> - -#include "cpp_protect.hpp" -#include "NativeRegistry.hpp" - -namespace Rice::detail -{ - template <typename T, typename Iterator_Func_T> - inline void NativeIterator<T, Iterator_Func_T>::define(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end) - { - // Tell Ruby to invoke the static method call on this class - detail::protect(rb_define_method, klass, method_name.c_str(), (RUBY_METHOD_FUNC)&NativeIterator_T::call, 0); - - // Now create a NativeIterator instance and save it to the natives registry keyed on - // Ruby klass and method id. There may be multiple NativeIterator instances - // because the same C++ method could be mapped to multiple Ruby methods. - NativeIterator_T* native = new NativeIterator_T(klass, method_name, begin, end); - detail::Registries::instance.natives.add(klass, Identifier(method_name).id(), native); - } - - template<typename T, typename Iterator_Func_T> - inline VALUE NativeIterator<T, Iterator_Func_T>::call(VALUE self) - { - // Look up the native function based on the Ruby klass and method id - NativeIterator_T* nativeIterator = detail::Registries::instance.natives.lookup<NativeIterator_T*>(); - - return cpp_protect([&] - { - return nativeIterator->operator()(self); - }); - } - - template <typename T, typename Iterator_Func_T> - inline NativeIterator<T, Iterator_Func_T>::NativeIterator(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end) : - klass_(klass), method_name_(method_name), begin_(begin), end_(end) - { - } - - template<typename T, typename Iterator_Func_T> - inline VALUE NativeIterator<T, Iterator_Func_T>::createRubyEnumerator(VALUE self) - { - auto rb_size_function = [](VALUE recv, VALUE argv, VALUE eobj) -> VALUE - { - // Since we can't capture VALUE self from above (because then we can't send - // this lambda to rb_enumeratorize_with_size), extract it from recv - return cpp_protect([&] - { - // Get the iterator instance - using Iter_T = NativeIterator<T, Iterator_Func_T>; - // Class is easy - VALUE klass = protect(rb_class_of, recv); - // Read the method_id from an attribute we added to the enumerator instance - ID method_id = protect(rb_ivar_get, eobj, rb_intern("rice_method")); - Iter_T* iterator = detail::Registries::instance.natives.lookup<Iter_T*>(klass, method_id); - - // Get the wrapped C++ instance - T* receiver = detail::From_Ruby<T*>().convert(recv); - - // Get the distance - Iterator_T begin = std::invoke(iterator->begin_, *receiver); - Iterator_T end = std::invoke(iterator->end_, *receiver); - Difference_T distance = std::distance(begin, end); - - return detail::To_Ruby<Difference_T>().convert(distance); - }); - }; - - VALUE method_sym = Identifier(this->method_name_).to_sym(); - VALUE enumerator = protect(rb_enumeratorize_with_size, self, method_sym, 0, nullptr, rb_size_function); - - // Hack the enumerator object by storing name_ on the enumerator object so - // the rb_size_function above has access to it - ID method_id = Identifier(this->method_name_).id(); - protect(rb_ivar_set, enumerator, rb_intern("rice_method"), method_id); - - return enumerator; - } - - template<typename T, typename Iterator_Func_T> - inline VALUE NativeIterator<T, Iterator_Func_T>::operator()(VALUE self) - { - if (!protect(rb_block_given_p)) - { - return createRubyEnumerator(self); - } - else - { - T* receiver = detail::From_Ruby<T*>().convert(self); - Iterator_T it = std::invoke(this->begin_, *receiver); - Iterator_T end = std::invoke(this->end_, *receiver); - - for (; it != end; ++it) - { - protect(rb_yield, detail::To_Ruby<Value_T&>().convert(*it)); - } - - return self; - } - } +#include <iterator> +#include <functional> +#include <type_traits> + +#include "cpp_protect.hpp" +#include "NativeRegistry.hpp" + +namespace Rice::detail +{ + template <typename T, typename Iterator_Func_T> + inline void NativeIterator<T, Iterator_Func_T>::define(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end) + { + // Tell Ruby to invoke the static method call on this class + detail::protect(rb_define_method, klass, method_name.c_str(), (RUBY_METHOD_FUNC)&NativeIterator_T::call, 0); + + // Now create a NativeIterator instance and save it to the natives registry keyed on + // Ruby klass and method id. There may be multiple NativeIterator instances + // because the same C++ method could be mapped to multiple Ruby methods. + NativeIterator_T* native = new NativeIterator_T(klass, method_name, begin, end); + detail::Registries::instance.natives.add(klass, Identifier(method_name).id(), native); + } + + template<typename T, typename Iterator_Func_T> + inline VALUE NativeIterator<T, Iterator_Func_T>::call(VALUE self) + { + // Look up the native function based on the Ruby klass and method id + NativeIterator_T* nativeIterator = detail::Registries::instance.natives.lookup<NativeIterator_T*>(); + + return cpp_protect([&] + { + return nativeIterator->operator()(self); + }); + } + + template <typename T, typename Iterator_Func_T> + inline NativeIterator<T, Iterator_Func_T>::NativeIterator(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end) : + klass_(klass), method_name_(method_name), begin_(begin), end_(end) + { + } + + template<typename T, typename Iterator_Func_T> + inline VALUE NativeIterator<T, Iterator_Func_T>::createRubyEnumerator(VALUE self) + { + auto rb_size_function = [](VALUE recv, VALUE argv, VALUE eobj) -> VALUE + { + // Since we can't capture VALUE self from above (because then we can't send + // this lambda to rb_enumeratorize_with_size), extract it from recv + return cpp_protect([&] + { + // Get the iterator instance + using Iter_T = NativeIterator<T, Iterator_Func_T>; + // Class is easy + VALUE klass = protect(rb_class_of, recv); + // Read the method_id from an attribute we added to the enumerator instance + ID method_id = protect(rb_ivar_get, eobj, rb_intern("rice_method")); + Iter_T* iterator = detail::Registries::instance.natives.lookup<Iter_T*>(klass, method_id); + + // Get the wrapped C++ instance + T* receiver = detail::From_Ruby<T*>().convert(recv); + + // Get the distance + Iterator_T begin = std::invoke(iterator->begin_, *receiver); + Iterator_T end = std::invoke(iterator->end_, *receiver); + Difference_T distance = std::distance(begin, end); + + return detail::To_Ruby<Difference_T>().convert(distance); + }); + }; + + VALUE method_sym = Identifier(this->method_name_).to_sym(); + VALUE enumerator = protect(rb_enumeratorize_with_size, self, method_sym, 0, nullptr, rb_size_function); + + // Hack the enumerator object by storing name_ on the enumerator object so + // the rb_size_function above has access to it + ID method_id = Identifier(this->method_name_).id(); + protect(rb_ivar_set, enumerator, rb_intern("rice_method"), method_id); + + return enumerator; + } + + template<typename T, typename Iterator_Func_T> + inline VALUE NativeIterator<T, Iterator_Func_T>::operator()(VALUE self) + { + if (!protect(rb_block_given_p)) + { + return createRubyEnumerator(self); + } + else + { + T* receiver = detail::From_Ruby<T*>().convert(self); + Iterator_T it = std::invoke(this->begin_, *receiver); + Iterator_T end = std::invoke(this->end_, *receiver); + + for (; it != end; ++it) + { + protect(rb_yield, detail::To_Ruby<Value_T&>().convert(*it)); + } + + return self; + } + } } \ No newline at end of file