/* * Copyright 2019 by its authors. See AUTHORS. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _EFL_ECORE_CXX_ECORE_MANUAL_HH #define _EFL_ECORE_CXX_ECORE_MANUAL_HH #include #include #include #include #include #include namespace efl { namespace ecore { template struct _identity { typedef T type; }; template void _ecore_main_loop_thread_safe_call_async_callback(void* data) { std::unique_ptr f (static_cast(data)); try { (*f)(); } catch(std::bad_alloc const& e) { eina_error_set(ENOMEM); } catch(std::system_error const& e) { efl::eina::set_error_code(e.code()); } catch(...) { eina_error_set( efl::eina::unknown_error() ); } } template struct _return_buffer { typename std::aligned_storage::value>::type buffer; }; template <> struct _return_buffer { }; template struct _data { F& f; std::exception_ptr exception; typedef typename std::result_of::type result_type; _return_buffer return_buffer; }; template void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data* d, _identity) { d->f(); if(eina_error_get()) d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); return 0; } template void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data* d, _identity) { typedef R result_type; new (&d->return_buffer.buffer) result_type ( std::move(d->f()) ); if(eina_error_get()) { d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); eina_error_set(0); result_type* p = static_cast(static_cast(&d->return_buffer.buffer)); p->~result_type(); } return 0; } template void* _ecore_main_loop_thread_safe_call_sync_callback(void* data) { _data* d = static_cast<_data*>(data); try { return _ecore_main_loop_thread_safe_call_sync_callback_aux (d, _identity::type>()); } catch(std::bad_alloc const& e) { d->exception = std::current_exception(); } catch(std::system_error const& e) { d->exception = std::current_exception(); } catch(...) { d->exception = std::current_exception(); } return 0; } template void main_loop_thread_safe_call_async(F&& f) { ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback , new F(std::forward(f)) ); } template void _get_return_value(_data& data, _identity) { if(data.exception) { std::rethrow_exception(data.exception); } } template R _get_return_value(_data& data, _identity) { if(!data.exception) { R* b_ = static_cast(static_cast(&data.return_buffer.buffer)); struct destroy { destroy(R* x_) : p_(x_) {} ~destroy() { p_->~R(); } R* p_; } destroy_temp(b_); return std::move(*b_); } else { std::rethrow_exception(data.exception); } } template typename std::result_of::type main_loop_thread_safe_call_sync(F&& f) { typedef typename std::result_of::type result_type; _data data {f, nullptr, {}}; ::ecore_main_loop_thread_safe_call_sync (&ecore::_ecore_main_loop_thread_safe_call_sync_callback, &data); return _get_return_value(data, _identity()); } struct ecore_init { ecore_init() { ::ecore_init(); } ~ecore_init() { ::ecore_shutdown(); } }; } } #endif