summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2014-02-26 18:37:21 -0300
committerCedric Bail <cedric.bail@free.fr>2014-02-26 18:52:08 -0300
commit91f5a9b0431ed6ba1adab28fff0a3fab7fc65211 (patch)
tree289669014b5c543d06db1ed82a3275dcadfc2f8f /src
parent3312ba4c56f352d774ef72273242392c2a110f96 (diff)
ecore_cxx: add main_loop_thread_safe_call_sync and main_loop_thread_safe_call_async with tests
The point of this binding is to enable the support for easy lambda for ecore function that wont be using Eo. See the tests on how to use those. Reviewers: cedric, raster CC: savio, cedric Differential Revision: https://phab.enlightenment.org/D582 Signed-off-by: Cedric Bail <cedric.bail@free.fr>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile_Ecore_Cxx.am36
-rw-r--r--src/bindings/ecore_cxx/Ecore.hh123
-rw-r--r--src/tests/ecore_cxx/ecore_cxx_suite.cc103
-rw-r--r--src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc193
5 files changed, 456 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 9abc8a919d..b2ac30d76a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -27,6 +27,7 @@ include Makefile_Eo.am
27include Makefile_Eet.am 27include Makefile_Eet.am
28include Makefile_Evas.am 28include Makefile_Evas.am
29include Makefile_Ecore.am 29include Makefile_Ecore.am
30include Makefile_Ecore_Cxx.am
30include Makefile_Ecore_Con.am 31include Makefile_Ecore_Con.am
31include Makefile_Ecore_Ipc.am 32include Makefile_Ecore_Ipc.am
32include Makefile_Ecore_File.am 33include Makefile_Ecore_File.am
diff --git a/src/Makefile_Ecore_Cxx.am b/src/Makefile_Ecore_Cxx.am
new file mode 100644
index 0000000000..ff8efdca86
--- /dev/null
+++ b/src/Makefile_Ecore_Cxx.am
@@ -0,0 +1,36 @@
1
2### Library
3
4installed_ecorecxxmainheadersdir = $(includedir)/ecore_cxx-@VMAJ@
5dist_installed_ecorecxxmainheaders_DATA = \
6bindings/ecore_cxx/Ecore.hh
7
8### Unit tests
9
10if EFL_ENABLE_TESTS
11if HAVE_CXX11
12
13check_PROGRAMS += tests/ecore_cxx/ecore_cxx_suite
14TESTS += tests/ecore_cxx/ecore_cxx_suite
15
16tests_ecore_cxx_ecore_cxx_suite_SOURCES = \
17tests/ecore_cxx/ecore_cxx_suite.cc \
18tests/ecore_cxx/ecore_cxx_test_safe_call.cc
19
20tests_ecore_cxx_ecore_cxx_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
21-I$(top_srcdir)/src/bindings/ecore_cxx \
22-I$(top_srcdir)/src/bindings/eina_cxx \
23-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/ecore_cxx\" \
24-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/ecore_cxx\" \
25@CHECK_CFLAGS@ \
26@ECORE_CFLAGS@ \
27@EINA_CFLAGS@
28
29tests_ecore_cxx_ecore_cxx_suite_LDADD = \
30@CHECK_LIBS@ \
31@USE_ECORE_LIBS@
32tests_ecore_cxx_ecore_cxx_suite_DEPENDENCIES = \
33@USE_ECORE_INTERNAL_LIBS@
34
35endif
36endif
diff --git a/src/bindings/ecore_cxx/Ecore.hh b/src/bindings/ecore_cxx/Ecore.hh
new file mode 100644
index 0000000000..9d2dd0bf78
--- /dev/null
+++ b/src/bindings/ecore_cxx/Ecore.hh
@@ -0,0 +1,123 @@
1#ifndef _EFL_ECORE_CXX_ECORE_HH
2#define _EFL_ECORE_CXX_ECORE_HH
3
4#include <Ecore.h>
5
6#include <utility>
7#include <type_traits>
8#include <memory>
9#include <cstring>
10
11namespace efl { namespace ecore {
12
13template <typename T, typename Enable = void>
14struct _ecore_result_type_marshaller;
15
16template <typename T>
17struct _ecore_result_type_marshaller
18 <T, typename std::enable_if<std::is_pointer<T>::value>::type>
19{
20 static void* to_void(T o)
21 {
22 return static_cast<void*>(o);
23 }
24 static T from_void(void* o)
25 {
26 return static_cast<T>(o);
27 }
28};
29
30template <typename T>
31struct _ecore_result_type_marshaller
32 <T, typename std::enable_if<!std::is_pointer<T>::value && std::is_pod<T>::value
33 && sizeof(T) <= sizeof(void*)>::type>
34{
35 static void* to_void(T&& o)
36 {
37 unsigned char buf[sizeof(void*)];
38 T* p = static_cast<T*>(static_cast<void*>(&buf[0]));
39 new (p) T(std::move(o));
40 void* store;
41 std::memcpy(&store, buf, sizeof(void*));
42 return store;
43 }
44 static T from_void(void* store)
45 {
46 T* p = static_cast<T*>(static_cast<void*>(&store));
47 struct destroy_T
48 {
49 destroy_T(T& p)
50 : p(p) {}
51 ~destroy_T()
52 {
53 p.~T();
54 }
55 T& p;
56 } destroy(*p);
57 return T(std::move(*p));
58 }
59};
60
61template <typename T>
62struct _ecore_result_type_marshaller
63<T, typename std::enable_if<(sizeof(T) > sizeof(void*)) || !std::is_pod<T>::value>::type>
64{
65 static void* to_void(T&& o)
66 {
67 return new T(o);
68 }
69 static T from_void(void* store)
70 {
71 std::unique_ptr<T> p(static_cast<T*>(store));
72 return T(std::move(*p.get()));
73 }
74};
75
76template <typename F>
77void _ecore_main_loop_thread_safe_call_async_callback(void* data)
78{
79 F* f = static_cast<F*>(data);
80 (*f)();
81 delete f;
82}
83
84template <typename F>
85void* _ecore_main_loop_thread_safe_call_sync_callback(void* data)
86{
87 F* f = static_cast<F*>(data);
88 typedef typename std::result_of<F()>::type result_type;
89 return _ecore_result_type_marshaller<result_type>::to_void((*f)());
90}
91
92template <typename F>
93void main_loop_thread_safe_call_async(F&& f)
94{
95 ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback<F>
96 , new F(std::move(f)) );
97}
98
99template <typename F>
100typename std::result_of<F()>::type
101main_loop_thread_safe_call_sync(F&& f)
102{
103 void* d = ::ecore_main_loop_thread_safe_call_sync
104 (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &f);
105 typedef typename std::result_of<F()>::type result_type;
106 return _ecore_result_type_marshaller<result_type>::from_void(d);
107}
108
109struct ecore_init
110{
111 ecore_init()
112 {
113 ::ecore_init();
114 }
115 ~ecore_init()
116 {
117 ::ecore_shutdown();
118 }
119};
120
121} }
122
123#endif
diff --git a/src/tests/ecore_cxx/ecore_cxx_suite.cc b/src/tests/ecore_cxx/ecore_cxx_suite.cc
new file mode 100644
index 0000000000..9394672cd5
--- /dev/null
+++ b/src/tests/ecore_cxx/ecore_cxx_suite.cc
@@ -0,0 +1,103 @@
1
2#include "Ecore.hh"
3
4#include <cassert>
5#include <algorithm>
6
7#include <check.h>
8
9void ecore_test_safe_call(TCase* tc);
10
11typedef struct _Ecore_Test_Case Ecore_Test_Case;
12struct _Ecore_Test_Case
13{
14 const char *test_case;
15 void (*build)(TCase *tc);
16};
17
18static const Ecore_Test_Case etc[] = {
19 { "Safe_Call", ecore_test_safe_call },
20 { NULL, NULL }
21};
22
23static void
24_list_tests(void)
25{
26 const Ecore_Test_Case *itr = etc;
27 fputs("Available Test Cases:\n", stderr);
28 for (; itr->test_case; itr++)
29 fprintf(stderr, "\t%s\n", itr->test_case);
30}
31
32static Eina_Bool
33_use_test(int argc, const char **argv, const char *test_case)
34{
35 if (argc < 1)
36 return 1;
37
38 for (; argc > 0; argc--, argv++)
39 if (strcmp(test_case, *argv) == 0)
40 return 1;
41
42 return 0;
43}
44
45Suite *
46ecore_build_suite(int argc, const char **argv)
47{
48 TCase *tc;
49 Suite *s;
50 int i;
51
52 s = suite_create("Ecore");
53
54 for (i = 0; etc[i].test_case; ++i)
55 {
56 if (!_use_test(argc, argv, etc[i].test_case))
57 continue;
58
59 tc = tcase_create(etc[i].test_case);
60 tcase_set_timeout(tc, 0);
61
62 etc[i].build(tc);
63 suite_add_tcase(s, tc);
64 }
65
66 return s;
67}
68
69int main(int argc, char* argv[])
70{
71 Suite *s;
72 SRunner *sr;
73 int i, failed_count;
74
75 for (i = 1; i < argc; i++)
76 if ((strcmp(argv[i], "-h") == 0) ||
77 (strcmp(argv[i], "--help") == 0))
78 {
79 fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n",
80 argv[0]);
81 _list_tests();
82 return 0;
83 }
84 else if ((strcmp(argv[i], "-l") == 0) ||
85 (strcmp(argv[i], "--list") == 0))
86 {
87 _list_tests();
88 return 0;
89 }
90
91 putenv(const_cast<char*>("EFL_RUN_IN_TREE=1"));
92
93 s = ecore_build_suite(argc - 1, (const char **)argv + 1);
94 sr = srunner_create(s);
95
96 srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
97
98 srunner_run_all(sr, CK_ENV);
99 failed_count = srunner_ntests_failed(sr);
100 srunner_free(sr);
101
102 return (failed_count == 0) ? 0 : 255;
103}
diff --git a/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc b/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc
new file mode 100644
index 0000000000..bc2b78d4f3
--- /dev/null
+++ b/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc
@@ -0,0 +1,193 @@
1
2#include "Ecore.hh"
3#include "Eina.hh"
4
5#include <algorithm>
6
7#include <iostream>
8
9#include <check.h>
10
11void call_async(efl::eina::mutex& mutex, efl::eina::condition_variable& cond, bool& done)
12{
13 efl::ecore::main_loop_thread_safe_call_async
14 (
15 [&mutex,&cond,&done]
16 {
17 std::cout << "yeah" << std::endl;
18 ecore_main_loop_quit();
19 efl::eina::unique_lock<efl::eina::mutex> l(mutex);
20 std::cout << "mutex locked" << std::endl;
21 done = true;
22 cond.notify_one();
23 std::cout << "exiting" << std::endl;
24 }
25 );
26}
27
28START_TEST(ecore_cxx_safe_call_async)
29{
30 efl::ecore::ecore_init init;
31
32 efl::eina::mutex mutex;
33 efl::eina::condition_variable cond;
34 bool done = false;
35 efl::eina::thread thread(&call_async, std::ref(mutex), std::ref(cond), std::ref(done));
36
37 ecore_main_loop_begin();
38
39 std::cout << "joining" << std::endl;
40
41 thread.join();
42
43 std::cout << "joined" << std::endl;
44
45 efl::eina::unique_lock<efl::eina::mutex> l(mutex);
46 while(!done)
47 {
48 std::cout << "waiting" << std::endl;
49 cond.wait(l);
50 std::cout << "waited" << std::endl;
51 }
52
53 std::cout << "end of ecore_cxx_safe_call_async" << std::endl;
54}
55END_TEST
56
57struct big_pod
58{
59 double x;
60 double y;
61};
62
63int constructor_called = 0
64 , destructor_called = 0;
65
66struct small_nonpod
67{
68 small_nonpod()
69 : c(5)
70 {
71 constructor_called++;
72 }
73 small_nonpod(small_nonpod const& other)
74 : c(5)
75 {
76 ck_assert(other.c == 5);
77 constructor_called++;
78 }
79 ~small_nonpod()
80 {
81 ck_assert(c == 5);
82 destructor_called++;
83 }
84 char c;
85};
86
87struct big_nonpod : big_pod
88{
89 big_nonpod()
90 {
91 constructor_called++;
92 x = 2.0;
93 y = 1.0;
94 }
95 big_nonpod(big_nonpod const& other)
96 {
97 x = 2.0;
98 y = 1.0;
99 ck_assert(other.x == 2.0);
100 ck_assert(other.y == 1.0);
101 constructor_called++;
102 }
103 ~big_nonpod()
104 {
105 ck_assert(x == 2.0);
106 ck_assert(y == 1.0);
107 destructor_called++;
108 }
109 char c;
110};
111
112void call_sync_int()
113{
114 std::cout << "call_sync_init" << std::endl;
115 int r1 =
116 efl::ecore::main_loop_thread_safe_call_sync
117 (
118 [] () -> int
119 {
120 return 1;
121 }
122 );
123 ck_assert(r1 == 1);
124
125 std::cout << "big_pod" << std::endl;
126
127 big_pod r2 =
128 efl::ecore::main_loop_thread_safe_call_sync
129 (
130 [] () -> big_pod
131 {
132 return {1.0, 2.0};
133 }
134 );
135 ck_assert(r2.x == 1.0);
136 ck_assert(r2.y == 2.0);
137
138 std::cout << "small_nonpod" << std::endl;
139
140 {
141 small_nonpod r3 =
142 efl::ecore::main_loop_thread_safe_call_sync
143 (
144 [] () -> small_nonpod
145 {
146 return small_nonpod();
147 }
148 );
149 }
150 std::cout << "constructor_called: " << constructor_called << std::endl;
151 std::cout << "destructor_called: " << destructor_called << std::endl;
152 ck_assert(constructor_called == destructor_called);
153
154 std::cout << "big_nonpod" << std::endl;
155
156 {
157 big_nonpod r3 =
158 efl::ecore::main_loop_thread_safe_call_sync
159 (
160 [] () -> big_nonpod
161 {
162 std::cout << "before quit" << std::endl;
163 ecore_main_loop_quit();
164 std::cout << "are we calling here" << std::endl;
165 return big_nonpod();
166 }
167 );
168 }
169 std::cout << "constructor_called: " << constructor_called << std::endl;
170 std::cout << "destructor_called: " << destructor_called << std::endl;
171 ck_assert(constructor_called == destructor_called);
172}
173
174START_TEST(ecore_cxx_safe_call_sync)
175{
176 efl::ecore::ecore_init init;
177
178 efl::eina::thread thread(&call_sync_int);
179
180 ecore_main_loop_begin();
181
182 std::cout << "out of the loop" << std::endl;
183
184 thread.join();
185}
186END_TEST
187
188void
189ecore_test_safe_call(TCase* tc)
190{
191 tcase_add_test(tc, ecore_cxx_safe_call_async);
192 tcase_add_test(tc, ecore_cxx_safe_call_sync);
193}