summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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}