Skip to content

Commit

Permalink
Support basic type pointers for params #116
Browse files Browse the repository at this point in the history
- Add mapping for ValueMapper for T*
- Have to register basic types so that they can be passed as UserObject refs. Not ideal.
- Refs have ambiguity.
  • Loading branch information
billyquith committed Feb 17, 2019
1 parent 189efbc commit d8e8556
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 14 deletions.
6 changes: 5 additions & 1 deletion include/ponder/detail/valueimpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,15 @@ struct ConvertVisitor
return ponder_ext::ValueMapper<T>::from(value);
}

// Optimization when source type is the same as requested type
T operator()(const T& value) const
{
// Optimization when source type is the same as requested type
return value;
}
T operator()(T&& value) const
{
return std::move(value);
}

T operator()(NoType) const
{
Expand Down
2 changes: 1 addition & 1 deletion include/ponder/uses/detail/runtime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ struct ChooseCallReturner<std::tuple<policy::ReturnInternalRef, Ps...>, R>
};

template <typename R>
struct ChooseCallReturner<std::tuple<>, R> // default
struct ChooseCallReturner<std::tuple<>, R> // default
{
typedef CallReturnCopy<R> type;
};
Expand Down
29 changes: 25 additions & 4 deletions include/ponder/value.inl
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,40 @@ template <typename T> struct IsUserObjRef {
static constexpr bool value = std::is_pointer<T>::value || std::is_reference<T>::value;
};

/**
* \brief Helper structure allowing a shortcut when converting a ponder::Value to type
*/
template <typename T>

// Convert ponder::Value to type
template <typename T, typename E = void>
struct ValueTo
{
static T convert(const Value& value) {return value.visit(ConvertVisitor<T>());}
};

// Don't need to convert, we're returning a Value
template <>
struct ValueTo<Value>
{
static Value convert(const Value& value) {return value;}
static Value convert(Value&& value) {return std::move(value);}
};

// Convert Values to pointers for basic types
template <typename T>
struct ValueTo<T*, typename std::enable_if<!hasStaticTypeDecl<T>()>::type>
{
static T* convert(const Value& value)
{
return static_cast<T*>(value.to<UserObject>().pointer());
}
};

// Convert Values to references for basic types
template <typename T>
struct ValueTo<T&, typename std::enable_if<!hasStaticTypeDecl<T>()>::type>
{
static T convert(const Value& value)
{
return *static_cast<T*>(value.to<UserObject>().pointer());
}
};

} // namespace detail
Expand Down
59 changes: 54 additions & 5 deletions include/ponder/valuemapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace ponder_ext {
*
* \brief Template providing a mapping between C++ types/values and Ponder types/values
*
* ValueMapper<T> defines a mapping to and from type T. It defines three things in
* ValueMapper<T> defines a mapping to and from type T to a Value. It defines three things in
* order to make T fully compliant with the system:
*
* \li The abstract Ponder type that T is mapped to
Expand Down Expand Up @@ -157,12 +157,62 @@ struct ValueMapper
* Specialization of ValueMapper for abstract types
*/
template <typename T>
struct ValueMapper<T, typename std::enable_if<std::is_abstract<T>::value >::type>
struct ValueMapper<T, typename std::enable_if<std::is_abstract<T>::value>::type>
{
static const ponder::ValueKind kind = ponder::ValueKind::User;
static ponder::UserObject to(const T& source) {return ponder::UserObject(source);}
};

/**
* Specialization of ValueMapper for pointers to basic types
* - Used for pass by-reference parameters that are non-registered types.
*/
template <typename T>
struct ValueMapper<T*, typename std::enable_if<!ponder::detail::hasStaticTypeDecl<T>()>::type>
{
static const ponder::ValueKind kind = ponder::ValueKind::User;

static ponder::UserObject to(T* source) {return ponder::UserObject::makeRef(source);}

static T* from(const ponder::UserObject& source) {return static_cast<T*>(source.pointer());}

static T from(bool)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Boolean,ponder::mapType<T>()));}
static T from(long)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Integer,ponder::mapType<T>()));}
static T from(double)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Real, ponder::mapType<T>()));}
static T from(const ponder::String&)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::String, ponder::mapType<T>()));}
static T from(const ponder::EnumObject&)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Enum, ponder::mapType<T>()));}
};

/**
* Specialization of ValueMapper for pointers to basic types
* - Used for pass by-reference parameters that are non-registered types.
*/
template <typename T>
struct ValueMapper<T&, typename std::enable_if<!ponder::detail::hasStaticTypeDecl<T>()>::type>
{
static const ponder::ValueKind kind = ponder::ValueKind::User;

static ponder::UserObject to(T& source) {return ponder::UserObject::makeRef(source);}

static T from(const ponder::UserObject& source) {return *static_cast<T*>(source.pointer());}

static T from(bool)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Boolean,ponder::mapType<T>()));}
static T from(long)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Integer,ponder::mapType<T>()));}
static T from(double)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Real, ponder::mapType<T>()));}
static T from(const ponder::String&)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::String, ponder::mapType<T>()));}
static T from(const ponder::EnumObject&)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::Enum, ponder::mapType<T>()));}
};

/**
* Specialization of ValueMapper for booleans
*/
Expand Down Expand Up @@ -197,8 +247,7 @@ struct ValueMapper<T,
static T from(long source) {return static_cast<T>(source);}
static T from(double source) {return static_cast<T>(source);}
static T from(const ponder::String& source) {return ponder::detail::convert<T>(source);}
static T from(const ponder::EnumObject& source)
{return static_cast<T>(source.value());}
static T from(const ponder::EnumObject& source) {return static_cast<T>(source.value());}
static T from(const ponder::UserObject&)
{PONDER_ERROR(ponder::BadType(ponder::ValueKind::User, ponder::ValueKind::Integer));}
};
Expand Down Expand Up @@ -453,7 +502,7 @@ struct ValueMapper<const T&>
*/
template <template <typename> class T, typename U>
struct ValueMapper<T<U>,
typename std::enable_if< ponder::detail::IsSmartPointer<T<U>,U>::value>::type>
typename std::enable_if<ponder::detail::IsSmartPointer<T<U>,U>::value>::type>
{
typedef int ReferencesNotAllowed[-(int)sizeof(U)];
};
Expand Down
67 changes: 64 additions & 3 deletions test/ponder/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ namespace FunctionTest
}
};

void nonMember1(MyClass& object) // TODO - allow non-const refs
void nonMember1(MyClass& object)
{
object.p1 = true;
}
Expand All @@ -167,7 +167,30 @@ namespace FunctionTest
return object->p3;
}

int refParam1(int a, const int *b)
{
assert(b != nullptr);
return a + *b;
}

// return value via param
void refParam2(float *sum, const float *value)
{
assert(sum != nullptr);
assert(value != nullptr);
*sum += *value;
}

int refParam3(int a, const int &b)
{
return a + b;
}

void refParam4(float &sum, const float &value)
{
sum += value;
}

class DataHolder
{
public:
Expand Down Expand Up @@ -203,6 +226,9 @@ namespace FunctionTest
.value("One", One)
.value("Two", Two);

ponder::Class::declare<int>();
ponder::Class::declare<float>();

ponder::Class::declare<MyType>();

ponder::Class::declare<NonCopyable>();
Expand All @@ -216,6 +242,10 @@ namespace FunctionTest
.function("nonMember1", &nonMember1) // object by reference
.function("nonMember2", &nonMember2) // object by value + parameter
.function("nonMember3", &nonMember3) // object by pointer
.function("refParam1", &refParam1) // params are refs/"out" pointer
.function("refParam2", &refParam2) // params are refs/"out" pointer
// .function("refParam3", &refParam3) // params are refs/"out" reference
// .function("refParam4", &refParam4) // params are refs/"out" reference

// ***** member functions *****
.function("member1", &MyClass::member1) // non-const
Expand Down Expand Up @@ -288,6 +318,8 @@ PONDER_AUTO_TYPE(FunctionTest::MyBase, &FunctionTest::declare)
PONDER_AUTO_TYPE(FunctionTest::DataHolder, &FunctionTest::declare)
PONDER_AUTO_TYPE(FunctionTest::DataModifier, &FunctionTest::declare)
PONDER_AUTO_TYPE(FunctionTest::Policy, &FunctionTest::declare)
PONDER_TYPE(int) // TODO: remove necessity to do this
PONDER_TYPE(float)

using namespace FunctionTest;

Expand All @@ -298,6 +330,8 @@ struct FunctionTestFixture
, fn_nonMember1(metaclass.function("nonMember1"))
, fn_nonMember2(metaclass.function("nonMember2"))
, fn_nonMember3(metaclass.function("nonMember3"))
, fn_refParam1(metaclass.function("refParam1"))
, fn_refParam2(metaclass.function("refParam2"))
, fn_member1(metaclass.function("member1"))
, fn_member2(metaclass.function("member2"))
, fn_member3(metaclass.function("member3"))
Expand Down Expand Up @@ -327,6 +361,8 @@ struct FunctionTestFixture
const ponder::Function &fn_nonMember1;
const ponder::Function &fn_nonMember2;
const ponder::Function &fn_nonMember3;
const ponder::Function &fn_refParam1;
const ponder::Function &fn_refParam2;
const ponder::Function &fn_member1;
const ponder::Function &fn_member2;
const ponder::Function &fn_member3;
Expand All @@ -350,8 +386,6 @@ struct FunctionTestFixture
const ponder::Function &fn_nonClassFunc2;
const ponder::Function &fn_nonCopyRef;
const ponder::Function &fn_nonCopyPtr;

const ponder::Function *functions[23];
};

//-----------------------------------------------------------------------------
Expand All @@ -365,6 +399,7 @@ TEST_CASE_METHOD(FunctionTestFixture, "Registered function properties can be int
IS_TRUE(fn_nonMember1.kind() == ponder::FunctionKind::Function);
IS_TRUE(fn_nonMember2.kind() == ponder::FunctionKind::Function);
IS_TRUE(fn_nonMember3.kind() == ponder::FunctionKind::Function);
IS_TRUE(fn_refParam1.kind() == ponder::FunctionKind::Function);

IS_TRUE(fn_member1.kind() == ponder::FunctionKind::MemberFunction);
IS_TRUE(fn_member2.kind() == ponder::FunctionKind::MemberFunction);
Expand Down Expand Up @@ -695,6 +730,32 @@ TEST_CASE_METHOD(FunctionTestFixture, "Registered functions can be called with t
Value ncr = callStatic(fn_nonCopyRef);
Value ncp = callStatic(fn_nonCopyPtr);
}

// Function params can be pointers, which may return values
SECTION("Function params can be references")
{
using namespace ponder::runtime;

int b = 7;
ponder::Value ret;
//ret = callStatic(fn_refParam1, ponder::Args(3, &b));
ret = callStatic(fn_refParam1, 3, &b);
REQUIRE(ret.to<int>() == 10);
}

SECTION("Function params can return results")
{
using namespace ponder::runtime;

float sum = 0;
float value = 7.5f;
ponder::Value ret;
callStatic(fn_refParam2, &sum, &value);
REQUIRE(sum == value);
value = 3.5f;
callStatic(fn_refParam2, &sum, &value);
REQUIRE(sum == 7.5f + 3.5f);
}

SECTION("Function call helpers can be used direct")
{
Expand Down

0 comments on commit d8e8556

Please sign in to comment.