Commit 51f08312 by Ben Clayton

Reactor: Handle more implicit casting for Call() arguments

Add cast() static method to the CToReactor trait specializations. Use this in CallHelper to automatically convert C to Reactor types. This was implicitly handled by (most) reactor types having a contructor that took the C type, but this does not work for more complex conversions, such as 'const char*' -> rr::Pointer<Byte>. This particular conversion is now automatically handled when using Call() to invoke a function with a 'const char*' parameter. This also allows developers to define custom cast functions by specializing rr::CToReactor for their own types. This change also swaps the naming of CToReactor and CToReactorT. CToReactor now has contains 'type' and 'cast', and the 'T' suffix is more in keeping with the C++ traits naming convention for aliasing the ::type. Bug: b/143479561 Change-Id: I81faae365b5cbe0e45055160cc0f5470cd4fb2de Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38028Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
parent 8df0aaf2
...@@ -118,7 +118,7 @@ private: ...@@ -118,7 +118,7 @@ private:
using CArgumentType = typename std::tuple_element<index, std::tuple<Arguments...>>::type; using CArgumentType = typename std::tuple_element<index, std::tuple<Arguments...>>::type;
template<int index> template<int index>
using RArgumentType = CToReactor<CArgumentType<index>>; using RArgumentType = CToReactorT<CArgumentType<index>>;
// Return the argument value with the given index. // Return the argument value with the given index.
template<int index> template<int index>
...@@ -151,7 +151,7 @@ private: ...@@ -151,7 +151,7 @@ private:
{ {
core.reset(new Nucleus()); core.reset(new Nucleus());
std::vector<Type*> types = {CToReactor<Arguments>::getType()...}; std::vector<Type*> types = {CToReactorT<Arguments>::getType()...};
for(auto type : types) for(auto type : types)
{ {
if(type != Void::getType()) if(type != Void::getType())
...@@ -160,7 +160,7 @@ private: ...@@ -160,7 +160,7 @@ private:
} }
} }
Nucleus::createCoroutine(CToReactor<Return>::getType(), arguments); Nucleus::createCoroutine(CToReactorT<Return>::getType(), arguments);
} }
template<typename Return, typename... Arguments> template<typename Return, typename... Arguments>
......
...@@ -4357,4 +4357,17 @@ namespace rr ...@@ -4357,4 +4357,17 @@ namespace rr
Nucleus::createFence(memoryOrder); Nucleus::createFence(memoryOrder);
} }
Bool CToReactor<bool>::cast(bool v) { return type(v); }
Byte CToReactor<uint8_t>::cast(uint8_t v) { return type(v); }
SByte CToReactor<int8_t>::cast(int8_t v) { return type(v); }
Short CToReactor<int16_t>::cast(int16_t v) { return type(v); }
UShort CToReactor<uint16_t>::cast(uint16_t v) { return type(v); }
Int CToReactor<int32_t>::cast(int32_t v) { return type(v); }
UInt CToReactor<uint32_t>::cast(uint32_t v) { return type(v); }
Float CToReactor<float>::cast(float v) { return type(v); }
Pointer<Byte> CToReactor<void*>::cast(void* v) { return ConstantPointer(v); }
Pointer<Byte> CToReactor<const char*>::cast(const char* v) { return ConstantPointer(v); }
// TODO: Long has no constructor that takes a uint64_t
// Long CToReactor<uint64_t>::cast(uint64_t v) { return type(v); }
} }
...@@ -2472,7 +2472,7 @@ namespace rr ...@@ -2472,7 +2472,7 @@ namespace rr
template <typename T> template <typename T>
inline Value* ValueOf(const T &v) inline Value* ValueOf(const T &v)
{ {
return ReactorType<T>(v).loadValue(); return ReactorType<T>::cast(v).loadValue();
} }
void Return(); void Return();
...@@ -2480,7 +2480,7 @@ namespace rr ...@@ -2480,7 +2480,7 @@ namespace rr
template<class T> template<class T>
void Return(const T &ret) void Return(const T &ret)
{ {
static_assert(CanBeUsedAsReturn< ReactorType<T> >::value, "Unsupported type for Return()"); static_assert(CanBeUsedAsReturn< ReactorTypeT<T> >::value, "Unsupported type for Return()");
Nucleus::createRet(ValueOf<T>(ret)); Nucleus::createRet(ValueOf<T>(ret));
// Place any unreachable instructions in an unreferenced block. // Place any unreachable instructions in an unreferenced block.
Nucleus::setInsertBlock(Nucleus::createBasicBlock()); Nucleus::setInsertBlock(Nucleus::createBasicBlock());
...@@ -2527,17 +2527,17 @@ namespace rr ...@@ -2527,17 +2527,17 @@ namespace rr
class FunctionT; class FunctionT;
template<typename Return, typename... Arguments> template<typename Return, typename... Arguments>
class FunctionT<Return(Arguments...)> : public Function<CToReactor<Return>(CToReactor<Arguments>...)> class FunctionT<Return(Arguments...)> : public Function<CToReactorT<Return>(CToReactorT<Arguments>...)>
{ {
public: public:
// Type of base class // Type of base class
using BaseType = Function<CToReactor<Return>(CToReactor<Arguments>...)>; using BaseType = Function<CToReactorT<Return>(CToReactorT<Arguments>...)>;
// Function type, e.g. void(int,float) // Function type, e.g. void(int,float)
using CFunctionType = Return(Arguments...); using CFunctionType = Return(Arguments...);
// Reactor function type, e.g. Void(Int, Float) // Reactor function type, e.g. Void(Int, Float)
using ReactorFunctionType = CToReactor<Return>(CToReactor<Arguments>...); using ReactorFunctionType = CToReactorT<Return>(CToReactorT<Arguments>...);
// Returned RoutineT type // Returned RoutineT type
using RoutineType = RoutineT<CFunctionType>; using RoutineType = RoutineT<CFunctionType>;
...@@ -3209,24 +3209,24 @@ namespace rr ...@@ -3209,24 +3209,24 @@ namespace rr
class CallHelper<Return(Arguments...)> class CallHelper<Return(Arguments...)>
{ {
public: public:
using RReturn = CToReactor<Return>; using RReturn = CToReactorT<Return>;
static inline RReturn Call(Return(fptr)(Arguments...), CToReactor<Arguments>... args) static inline RReturn Call(Return(fptr)(Arguments...), CToReactorT<Arguments>... args)
{ {
return RValue<RReturn>(rr::Call( return RValue<RReturn>(rr::Call(
ConstantPointer(reinterpret_cast<void*>(fptr)), ConstantPointer(reinterpret_cast<void*>(fptr)),
RReturn::getType(), RReturn::getType(),
{ ValueOf(args) ... }, { ValueOf(args) ... },
{ CToReactor<Arguments>::getType() ... })); { CToReactorT<Arguments>::getType() ... }));
} }
static inline RReturn Call(Pointer<Byte> fptr, CToReactor<Arguments>... args) static inline RReturn Call(Pointer<Byte> fptr, CToReactorT<Arguments>... args)
{ {
return RValue<RReturn>(rr::Call( return RValue<RReturn>(rr::Call(
fptr, fptr,
RReturn::getType(), RReturn::getType(),
{ ValueOf(args) ... }, { ValueOf(args) ... },
{ CToReactor<Arguments>::getType() ... })); { CToReactorT<Arguments>::getType() ... }));
} }
}; };
...@@ -3234,44 +3234,47 @@ namespace rr ...@@ -3234,44 +3234,47 @@ namespace rr
class CallHelper<void(Arguments...)> class CallHelper<void(Arguments...)>
{ {
public: public:
static inline void Call(void(fptr)(Arguments...), CToReactor<Arguments>... args) static inline void Call(void(fptr)(Arguments...), CToReactorT<Arguments>... args)
{ {
rr::Call(ConstantPointer(reinterpret_cast<void*>(fptr)), rr::Call(ConstantPointer(reinterpret_cast<void*>(fptr)),
Void::getType(), Void::getType(),
{ ValueOf(args) ... }, { ValueOf(args) ... },
{ CToReactor<Arguments>::getType() ... }); { CToReactorT<Arguments>::getType() ... });
} }
static inline void Call(Pointer<Byte> fptr, CToReactor<Arguments>... args) static inline void Call(Pointer<Byte> fptr, CToReactorT<Arguments>... args)
{ {
rr::Call(fptr, rr::Call(fptr,
Void::getType(), Void::getType(),
{ ValueOf(args) ... }, { ValueOf(args) ... },
{ CToReactor<Arguments>::getType() ... }); { CToReactorT<Arguments>::getType() ... });
} }
}; };
template <typename T>
inline ReactorTypeT<T> CastToReactor(const T& v) { return ReactorType<T>::cast(v); }
// Calls the function pointer fptr with the given arguments args. // Calls the function pointer fptr with the given arguments args.
template<typename Return, typename ... Arguments> template<typename Return, typename ... CArgs, typename ... RArgs>
inline CToReactor<Return> Call(Return(fptr)(Arguments...), CToReactor<Arguments>... args) inline CToReactorT<Return> Call(Return(fptr)(CArgs...), RArgs&&... args)
{ {
return CallHelper<Return(Arguments...)>::Call(fptr, args...); return CallHelper<Return(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
} }
// Calls the function pointer fptr with the given arguments args. // Calls the function pointer fptr with the given arguments args.
// Overload for calling functions with void return type. // Overload for calling functions with void return type.
template<typename ... Arguments> template<typename ... CArgs, typename ... RArgs>
inline void Call(void(fptr)(Arguments...), CToReactor<Arguments>... args) inline void Call(void(fptr)(CArgs...), RArgs&&... args)
{ {
CallHelper<void(Arguments...)>::Call(fptr, args...); CallHelper<void(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
} }
// Calls the function pointer fptr with the signature FUNCTION_SIGNATURE and // Calls the function pointer fptr with the signature FUNCTION_SIGNATURE and
// arguments. // arguments.
template<typename FUNCTION_SIGNATURE, typename ... Arguments> template<typename FUNCTION_SIGNATURE, typename ... RArgs>
inline void Call(Pointer<Byte> fptr, Arguments ... args) inline void Call(Pointer<Byte> fptr, RArgs&& ... args)
{ {
CallHelper<FUNCTION_SIGNATURE>::Call(fptr, args...); CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
} }
// Breakpoint emits an instruction that will cause the application to trap. // Breakpoint emits an instruction that will cause the application to trap.
......
...@@ -1144,11 +1144,10 @@ TEST(ReactorUnitTests, Call) ...@@ -1144,11 +1144,10 @@ TEST(ReactorUnitTests, Call)
struct Class struct Class
{ {
static int Callback(uint8_t *p, int i, float f) static int Callback(Class *p, int i, float f)
{ {
auto c = reinterpret_cast<Class*>(p); p->i = i;
c->i = i; p->f = f;
c->f = f;
return i + int(f); return i + int(f);
} }
...@@ -1156,27 +1155,51 @@ TEST(ReactorUnitTests, Call) ...@@ -1156,27 +1155,51 @@ TEST(ReactorUnitTests, Call)
float f = 0.0f; float f = 0.0f;
}; };
FunctionT<int(void*)> function;
{ {
FunctionT<int(void*)> function; Pointer<Byte> c = function.Arg<0>();
{ auto res = Call(Class::Callback, c, 10, 20.0f);
Pointer<Byte> c = function.Arg<0>(); Return(res);
auto res = Call(Class::Callback, c, 10, 20.0f); }
Return(res);
}
auto routine = function("one"); auto routine = function("one");
if(routine) Class c;
{ int res = routine(&c);
Class c; EXPECT_EQ(res, 30);
EXPECT_EQ(c.i, 10);
EXPECT_EQ(c.f, 20.0f);
}
int res = routine(&c); TEST(ReactorUnitTests, CallImplicitCast)
{
if (!rr::Caps.CallSupported)
{
SUCCEED() << "rr::Call() not supported";
return;
}
EXPECT_EQ(res, 30); struct Class
EXPECT_EQ(c.i, 10); {
EXPECT_EQ(c.f, 20.0f); static void Callback(Class *c, const char* s)
{
c->str = s;
} }
std::string str;
};
FunctionT<void(Class *c, const char *s)> function;
{
Pointer<Byte> c = function.Arg<0>();
Pointer<Byte> s = function.Arg<1>();
Call(Class::Callback, c, s);
} }
auto routine = function("one");
Class c;
routine(&c, "hello world");
EXPECT_EQ(c.str, "hello world");
} }
TEST(ReactorUnitTests, CallExternalCallRoutine) TEST(ReactorUnitTests, CallExternalCallRoutine)
...@@ -1309,14 +1332,14 @@ TEST(ReactorUnitTests, PreserveXMMRegisters) ...@@ -1309,14 +1332,14 @@ TEST(ReactorUnitTests, PreserveXMMRegisters)
} }
template <typename T> template <typename T>
class CToReactorCastTest : public ::testing::Test class CToReactorTCastTest : public ::testing::Test
{ {
public: public:
using CType = typename std::tuple_element<0, T>::type; using CType = typename std::tuple_element<0, T>::type;
using ReactorType = typename std::tuple_element<1, T>::type; using ReactorType = typename std::tuple_element<1, T>::type;
}; };
using CToReactorCastTestTypes = ::testing::Types using CToReactorTCastTestTypes = ::testing::Types
< // Subset of types that can be used as arguments. < // Subset of types that can be used as arguments.
// std::pair<bool, Bool>, FIXME(capn): Not supported as argument type by Subzero. // std::pair<bool, Bool>, FIXME(capn): Not supported as argument type by Subzero.
// std::pair<uint8_t, Byte>, FIXME(capn): Not supported as argument type by Subzero. // std::pair<uint8_t, Byte>, FIXME(capn): Not supported as argument type by Subzero.
...@@ -1328,9 +1351,9 @@ using CToReactorCastTestTypes = ::testing::Types ...@@ -1328,9 +1351,9 @@ using CToReactorCastTestTypes = ::testing::Types
std::pair<float, Float> std::pair<float, Float>
>; >;
TYPED_TEST_SUITE(CToReactorCastTest, CToReactorCastTestTypes); TYPED_TEST_SUITE(CToReactorTCastTest, CToReactorTCastTestTypes);
TYPED_TEST(CToReactorCastTest, Casts) TYPED_TEST(CToReactorTCastTest, Casts)
{ {
using CType = typename TestFixture::CType; using CType = typename TestFixture::CType;
using ReactorType = typename TestFixture::ReactorType; using ReactorType = typename TestFixture::ReactorType;
...@@ -1534,37 +1557,37 @@ int main(int argc, char **argv) ...@@ -1534,37 +1557,37 @@ int main(int argc, char **argv)
// Trait compile time checks. // // Trait compile time checks. //
//////////////////////////////// ////////////////////////////////
// Assert CToReactor resolves to expected types. // Assert CToReactorT resolves to expected types.
static_assert(std::is_same<CToReactor<void>, Void>::value, ""); static_assert(std::is_same<CToReactorT<void>, Void>::value, "");
static_assert(std::is_same<CToReactor<bool>, Bool>::value, ""); static_assert(std::is_same<CToReactorT<bool>, Bool>::value, "");
static_assert(std::is_same<CToReactor<uint8_t>, Byte>::value, ""); static_assert(std::is_same<CToReactorT<uint8_t>, Byte>::value, "");
static_assert(std::is_same<CToReactor<int8_t>, SByte>::value, ""); static_assert(std::is_same<CToReactorT<int8_t>, SByte>::value, "");
static_assert(std::is_same<CToReactor<int16_t>, Short>::value, ""); static_assert(std::is_same<CToReactorT<int16_t>, Short>::value, "");
static_assert(std::is_same<CToReactor<uint16_t>, UShort>::value, ""); static_assert(std::is_same<CToReactorT<uint16_t>, UShort>::value, "");
static_assert(std::is_same<CToReactor<int32_t>, Int>::value, ""); static_assert(std::is_same<CToReactorT<int32_t>, Int>::value, "");
static_assert(std::is_same<CToReactor<uint64_t>, Long>::value, ""); static_assert(std::is_same<CToReactorT<uint64_t>, Long>::value, "");
static_assert(std::is_same<CToReactor<uint32_t>, UInt>::value, ""); static_assert(std::is_same<CToReactorT<uint32_t>, UInt>::value, "");
static_assert(std::is_same<CToReactor<float>, Float>::value, ""); static_assert(std::is_same<CToReactorT<float>, Float>::value, "");
// Assert CToReactor for known pointer types resolves to expected types. // Assert CToReactorT for known pointer types resolves to expected types.
static_assert(std::is_same<CToReactor<void*>, Pointer<Byte>>::value, ""); static_assert(std::is_same<CToReactorT<void*>, Pointer<Byte>>::value, "");
static_assert(std::is_same<CToReactor<bool*>, Pointer<Bool>>::value, ""); static_assert(std::is_same<CToReactorT<bool*>, Pointer<Bool>>::value, "");
static_assert(std::is_same<CToReactor<uint8_t*>, Pointer<Byte>>::value, ""); static_assert(std::is_same<CToReactorT<uint8_t*>, Pointer<Byte>>::value, "");
static_assert(std::is_same<CToReactor<int8_t*>, Pointer<SByte>>::value, ""); static_assert(std::is_same<CToReactorT<int8_t*>, Pointer<SByte>>::value, "");
static_assert(std::is_same<CToReactor<int16_t*>, Pointer<Short>>::value, ""); static_assert(std::is_same<CToReactorT<int16_t*>, Pointer<Short>>::value, "");
static_assert(std::is_same<CToReactor<uint16_t*>, Pointer<UShort>>::value, ""); static_assert(std::is_same<CToReactorT<uint16_t*>, Pointer<UShort>>::value, "");
static_assert(std::is_same<CToReactor<int32_t*>, Pointer<Int>>::value, ""); static_assert(std::is_same<CToReactorT<int32_t*>, Pointer<Int>>::value, "");
static_assert(std::is_same<CToReactor<uint64_t*>, Pointer<Long>>::value, ""); static_assert(std::is_same<CToReactorT<uint64_t*>, Pointer<Long>>::value, "");
static_assert(std::is_same<CToReactor<uint32_t*>, Pointer<UInt>>::value, ""); static_assert(std::is_same<CToReactorT<uint32_t*>, Pointer<UInt>>::value, "");
static_assert(std::is_same<CToReactor<float*>, Pointer<Float>>::value, ""); static_assert(std::is_same<CToReactorT<float*>, Pointer<Float>>::value, "");
static_assert(std::is_same<CToReactor<uint16_t**>, Pointer<Pointer<UShort>>>::value, ""); static_assert(std::is_same<CToReactorT<uint16_t**>, Pointer<Pointer<UShort>>>::value, "");
static_assert(std::is_same<CToReactor<uint16_t***>, Pointer<Pointer<Pointer<UShort>>>>::value, ""); static_assert(std::is_same<CToReactorT<uint16_t***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
// Assert CToReactor for unknown pointer types resolves to Pointer<Byte>. // Assert CToReactorT for unknown pointer types resolves to Pointer<Byte>.
struct S{}; struct S{};
static_assert(std::is_same<CToReactor<S*>, Pointer<Byte>>::value, ""); static_assert(std::is_same<CToReactorT<S*>, Pointer<Byte>>::value, "");
static_assert(std::is_same<CToReactor<S**>, Pointer<Pointer<Byte>>>::value, ""); static_assert(std::is_same<CToReactorT<S**>, Pointer<Pointer<Byte>>>::value, "");
static_assert(std::is_same<CToReactor<S***>, Pointer<Pointer<Pointer<Byte>>>>::value, ""); static_assert(std::is_same<CToReactorT<S***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
// Assert IsRValue<> resolves true for RValue<> types. // Assert IsRValue<> resolves true for RValue<> types.
static_assert(IsRValue<RValue<Void>>::value, ""); static_assert(IsRValue<RValue<Void>>::value, "");
......
...@@ -62,22 +62,24 @@ namespace rr ...@@ -62,22 +62,24 @@ namespace rr
static constexpr bool value = true; static constexpr bool value = true;
}; };
// CToReactor<T> resolves to the corresponding Reactor type for the given C // CToReactorT<T> resolves to the corresponding Reactor type for the given C
// template type T. // template type T.
template<typename T, typename ENABLE = void> struct CToReactorT; template<typename T, typename ENABLE = void> struct CToReactor;
template<typename T> using CToReactor = typename CToReactorT<T>::type; template<typename T> using CToReactorT = typename CToReactor<T>::type;
// CToReactorT specializations for POD types. // CToReactor specializations for POD types.
template<> struct CToReactorT<void> { using type = Void; }; template<> struct CToReactor<void> { using type = Void; };
template<> struct CToReactorT<bool> { using type = Bool; }; template<> struct CToReactor<bool> { using type = Bool; static Bool cast(bool); };
template<> struct CToReactorT<uint8_t> { using type = Byte; }; template<> struct CToReactor<uint8_t> { using type = Byte; static Byte cast(uint8_t); };
template<> struct CToReactorT<int8_t> { using type = SByte; }; template<> struct CToReactor<int8_t> { using type = SByte; static SByte cast(int8_t); };
template<> struct CToReactorT<int16_t> { using type = Short; }; template<> struct CToReactor<int16_t> { using type = Short; static Short cast(int16_t); };
template<> struct CToReactorT<uint16_t> { using type = UShort; }; template<> struct CToReactor<uint16_t> { using type = UShort; static UShort cast(uint16_t); };
template<> struct CToReactorT<int32_t> { using type = Int; }; template<> struct CToReactor<int32_t> { using type = Int; static Int cast(int32_t); };
template<> struct CToReactorT<uint64_t> { using type = Long; }; template<> struct CToReactor<uint32_t> { using type = UInt; static UInt cast(uint32_t); };
template<> struct CToReactorT<uint32_t> { using type = UInt; }; template<> struct CToReactor<float> { using type = Float; static Float cast(float); };
template<> struct CToReactorT<float> { using type = Float; };
// TODO: Long has no constructor that takes a uint64_t
template<> struct CToReactor<uint64_t> { using type = Long; /* static Long cast(uint64_t); */ };
// CToReactorPtrT<T>::type resolves to the corresponding Reactor Pointer<> // CToReactorPtrT<T>::type resolves to the corresponding Reactor Pointer<>
// type for T*. // type for T*.
...@@ -86,32 +88,47 @@ namespace rr ...@@ -86,32 +88,47 @@ namespace rr
// CToReactorPtrT<T>::type resolves to Pointer<Byte>. // CToReactorPtrT<T>::type resolves to Pointer<Byte>.
template<typename T, typename ENABLE = void> struct CToReactorPtrT { using type = Pointer<Byte>; }; template<typename T, typename ENABLE = void> struct CToReactorPtrT { using type = Pointer<Byte>; };
template<typename T> using CToReactorPtr = typename CToReactorPtrT<T>::type; template<typename T> using CToReactorPtr = typename CToReactorPtrT<T>::type;
template<typename T> struct CToReactorPtrT<T, typename std::enable_if< IsDefined< typename CToReactorT<T>::type >::value>::type > template<typename T> struct CToReactorPtrT<T, typename std::enable_if< IsDefined< CToReactorT<T> >::value>::type >
{ {
using type = Pointer< typename CToReactorT<T>::type >; using type = Pointer< CToReactorT<T> >;
static type cast(T v) { return type(v); }
}; };
// CToReactorT specialization for pointer types. // CToReactor specialization for pointer types.
// For T types that have a CToReactorT<> specialization, // For T types that have a CToReactorT<> specialization,
// CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise // CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise
// CToReactorT<T*>::type resolves to Pointer<Byte>. // CToReactorT<T*>::type resolves to Pointer<Byte>.
template<typename T> template<typename T>
struct CToReactorT<T, typename std::enable_if<std::is_pointer<T>::value>::type> struct CToReactor<T, typename std::enable_if<std::is_pointer<T>::value>::type>
{ {
using elem = typename std::remove_pointer<T>::type; using elem = typename std::remove_pointer<T>::type;
using type = CToReactorPtr<elem>; using type = CToReactorPtr<elem>;
static type cast(T v) { return type(v); }
}; };
// CToReactorT specialization for void*. // CToReactor specialization for void*.
// Maps to Pointer<Byte> instead of Pointer<Void>. // Maps to Pointer<Byte> instead of Pointer<Void>.
template<> struct CToReactorT<void*> { using type = Pointer<Byte>; }; template<> struct CToReactor<void*>
{
using type = Pointer<Byte>;
static type cast(void* v);
};
// CToReactorT specialization for enum types. // CToReactor specialization for void*.
// Maps to Pointer<Byte> instead of Pointer<Void>.
template<> struct CToReactor<const char*>
{
using type = Pointer<Byte>;
static type cast(const char* v);
};
// CToReactor specialization for enum types.
template<typename T> template<typename T>
struct CToReactorT<T, typename std::enable_if<std::is_enum<T>::value>::type> struct CToReactor<T, typename std::enable_if<std::is_enum<T>::value>::type>
{ {
using underlying = typename std::underlying_type<T>::type; using underlying = typename std::underlying_type<T>::type;
using type = typename CToReactorT<underlying>::type; using type = CToReactorT<underlying>;
static type cast(T v) { return type(v); }
}; };
// IsRValue::value is true if T is of type RValue<X>, where X is any type. // IsRValue::value is true if T is of type RValue<X>, where X is any type.
...@@ -125,14 +142,30 @@ namespace rr ...@@ -125,14 +142,30 @@ namespace rr
template <typename T, typename Enable = void> struct IsReference { static constexpr bool value = false; }; template <typename T, typename Enable = void> struct IsReference { static constexpr bool value = false; };
template <typename T> struct IsReference<T, typename std::enable_if<IsDefined<typename T::reference_underlying_type>::value>::type> { static constexpr bool value = true; }; template <typename T> struct IsReference<T, typename std::enable_if<IsDefined<typename T::reference_underlying_type>::value>::type> { static constexpr bool value = true; };
// ReactorType<T> returns the LValue Reactor type for T. // ReactorTypeT<T> returns the LValue Reactor type for T.
// T can be a C-type, RValue or LValue. // T can be a C-type, RValue or LValue.
template<typename T, typename ENABLE = void> struct ReactorTypeT; template<typename T, typename ENABLE = void> struct ReactorType;
template<typename T> using ReactorType = typename ReactorTypeT<T>::type; template<typename T> using ReactorTypeT = typename ReactorType<T>::type;
template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsDefined<CToReactor<T>>::value>::type> { using type = CToReactor<T>; }; template<typename T> struct ReactorType<T, typename std::enable_if<IsDefined<CToReactorT<T>>::value>::type>
template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsRValue<T>::value>::type> { using type = typename T::rvalue_underlying_type; }; {
template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsLValue<T>::value>::type> { using type = T; }; using type = CToReactorT<T>;
template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsReference<T>::value>::type> { using type = T; }; static type cast(T v) { return CToReactor<T>::cast(v); }
};
template<typename T> struct ReactorType<T, typename std::enable_if<IsRValue<T>::value>::type>
{
using type = typename T::rvalue_underlying_type;
static type cast(T v) { return type(v); }
};
template<typename T> struct ReactorType<T, typename std::enable_if<IsLValue<T>::value>::type>
{
using type = T;
static type cast(T v) { return type(v); }
};
template<typename T> struct ReactorType<T, typename std::enable_if<IsReference<T>::value>::type>
{
using type = T;
static type cast(T v) { return type(v); }
};
// Reactor types that can be used as a return type for a function. // Reactor types that can be used as a return type for a function.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment