Skip to content

Commit

Permalink
support befriending specializations
Browse files Browse the repository at this point in the history
  • Loading branch information
jll63 committed Feb 9, 2020
1 parent b5ed76e commit 1ef82c1
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 7 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ if (${YOMM2_ENABLE_TESTS})
add_test (adventure examples/adventure)
add_test (next examples/next)
add_test (asteroids examples/asteroids)
add_test (friendship examples/friendship)
endif()

if (NOT DEFINED(YOMM2_ENABLE_BENCHMARKS))
Expand Down
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ add_executable(asteroids asteroids.cpp)
target_link_libraries (asteroids yomm2)
add_test (asteroids asteroids)

add_executable(friendship friendship.cpp)
target_link_libraries (friendship yomm2)
add_test (friendship friendship)

if(NOT MSVC)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
add_executable(dl_main dl_main.cpp)
Expand Down
88 changes: 88 additions & 0 deletions examples/friendship.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2020 Jean-Louis Leroy
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// This is based on sample code provided by Github user matpen in
// https://github.com/jll63/yomm2/issues/7

#include <yorel/yomm2/cute.hpp>

#include <iostream>
#include <memory>
#include <string>

using yorel::yomm2::virtual_;
using std::cout;

class Geometry
{
public:
virtual ~Geometry() {}
};

class Arc : public Geometry
{
public:
virtual ~Arc() {}
};

class Edge : public Geometry
{
public:
virtual ~Edge() {}
};

register_class(Geometry);
register_class(Arc, Geometry);
register_class(Edge, Geometry);

class Painter
{
public:
void paint(const Geometry& geometry);
private:
int counter = 0;
friend_named_method(paint_geo);
};

// Implements paint
declare_method(void, paintObject, (Painter&, virtual_<const Geometry&>));

// Catch-all paint(Geometry)
define_named_method(
paint_geo,
void, paintObject, (Painter& painter, const Geometry& /*geometry*/)) {
std::cout << "painting geometry (" << painter.counter << ")\n";
++painter.counter;
}

// Specific paint(Arc)
define_method(void, paintObject, (Painter& painter, const Arc& arc)) {
//next(painter, arc);
// also provides a way of calling a specific override:
call_named_method(paint_geo, (painter, arc));
std::cout << " painting arc\n";
}

// Specific paint(Edge)
define_method(void, paintObject, (Painter& painter, const Edge& edge)) {
next(painter, edge);
std::cout << " painting edge\n";
}

void Painter::paint(const Geometry& geometry)
{
paintObject(*this, geometry);
}

int main() {
yorel::yomm2::update_methods();

Arc arc;
Edge edge;
Painter painter;

painter.paint(arc);
painter.paint(edge);
}
38 changes: 35 additions & 3 deletions include/yorel/yomm2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,45 @@
using _yOMM2_method = _yOMM2_select<void ARGS>::type; \
using _yOMM2_return_t = _yOMM2_method::return_type; \
_yOMM2_return_t (*next) ARGS; \
struct _yOMM2_spec { static RETURN_T body ARGS; }; \
struct _yOMM2_spec { static RETURN_T yOMM2_body ARGS; }; \
::yorel::yomm2::detail:: \
register_spec<_yOMM2_return_t, _yOMM2_method, _yOMM2_spec, void ARGS> \
_yOMM2_init( \
(void**)&next, YOMM2_TRACE_ELSE(#ARGS, typeid(_yOMM2_spec).name())); \
} } \
RETURN_T NS::_yOMM2_spec::body ARGS
RETURN_T NS::_yOMM2_spec::yOMM2_body ARGS

#define YOMM2_DECLARE_NAMED_METHOD(CONTAINER) struct CONTAINER

#define YOMM2_FRIEND_NAMED_METHOD(CONTAINER) friend struct CONTAINER

#define YOMM2_NAMED_DEFINE(CONTAINER, RETURN_T, ID, ARGS) \
yOMM2_NAMED_DEFINE(yOMM2_GENSYM, CONTAINER, RETURN_T, ID, ARGS)

#define YOMM2_CALL_NAMED_METHOD(CONTAINER, ARGS) CONTAINER::yOMM2_body ARGS

#define yOMM2_NAMED_DEFINE(NS, CONTAINER, RETURN_T, ID, ARGS) \
namespace { namespace NS { \
template<typename T> struct _yOMM2_select; \
template<typename... A> struct _yOMM2_select<void(A...)> { \
using type = decltype(ID(::yorel::yomm2::detail::discriminator(), \
std::declval<A>()...)); \
}; \
using _yOMM2_method = _yOMM2_select<void ARGS>::type; \
using _yOMM2_return_t = _yOMM2_method::return_type; \
} } \
struct CONTAINER { \
static NS::_yOMM2_return_t (*next) ARGS; \
static RETURN_T yOMM2_body ARGS; \
}; \
NS::_yOMM2_return_t (*CONTAINER::next) ARGS; \
namespace { namespace NS { \
::yorel::yomm2::detail:: \
register_spec<_yOMM2_return_t, _yOMM2_method, CONTAINER, void ARGS> \
_yOMM2_init( \
(void**)&CONTAINER::next, YOMM2_TRACE_ELSE(#ARGS, typeid(CONTAINER).name())); \
} } \
RETURN_T CONTAINER::yOMM2_body ARGS

#define YOMM2_CLASS(...) \
yOMM2_CLASS2(yOMM2_GENSYM, \
Expand Down Expand Up @@ -801,7 +833,7 @@ template<
>
struct wrapper<BASE_RETURN, FUNCTION, BASE_RETURN(BASE_PARAM...), BASE_RETURN(SPEC_PARAM...)> {
static BASE_RETURN body(virtual_arg_t<BASE_PARAM>... arg) {
return FUNCTION::body(
return FUNCTION::yOMM2_body(
virtual_traits<BASE_PARAM>::template cast<SPEC_PARAM>(
std::forward<virtual_arg_t<BASE_PARAM>>(arg),
typename select_cast<
Expand Down
8 changes: 7 additions & 1 deletion include/yorel/yomm2/cute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@

#include <yorel/yomm2.hpp>

#define register_class YOMM2_CLASS

#define declare_method YOMM2_DECLARE
#define define_method YOMM2_DEFINE
#define register_class YOMM2_CLASS

#define declare_named_method YOMM2_DECLARE_NAMED_METHOD
#define define_named_method YOMM2_NAMED_DEFINE
#define call_named_method YOMM2_CALL_NAMED_METHOD
#define friend_named_method YOMM2_FRIEND_NAMED_METHOD

#endif
6 changes: 3 additions & 3 deletions tests/whitebox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,19 @@ struct Dog : Mammal, Carnivore {
};

struct get_this_mammal {
static const void* body(const Mammal& obj) {
static const void* yOMM2_body(const Mammal& obj) {
return &obj;
}
};

struct get_this_carnivore {
static const void* body(const Carnivore& obj) {
static const void* yOMM2_body(const Carnivore& obj) {
return &obj;
}
};

struct get_this_dog {
static const void* body(const Dog& obj) {
static const void* yOMM2_body(const Dog& obj) {
return &obj;
}
};
Expand Down

0 comments on commit 1ef82c1

Please sign in to comment.