Since this is my first attempt to submit code to the GNC project I thought
I'd pass my approach through the established
developers first.
I am interested in converting GNC code from C to C++ which will occur over
time so that the review quanta is not too overwhelming.
I plan to convert build targets to only use the C++ compiler over time.
Anything that is exposed with C linkage I plan to carry forward expecting at
some point all the callers will be C++ as well and most if not all of the
C-linkage requirements will go away.
Any C++ code that is called from C-code will need a mechanism to prevent C++
exceptions from bleeding back.
I've developed a header file except-fence.hpp that provides the required
fencing.
My first patch will be just this header file and the associated test files,
so no GNC code will be affected initially.
I wanted to make the footprint small since I expect the fences will
eventually be removed.
My approach is to replace the definition if the C-API functions with a macro
that defines a stub C-API (extern "C")
Which instantiates an ExceptFence object and uses the "forward_to" method
call a local static function with the original body.
For Example:
const char *
func1(int a, gpointer b) // defined as extern "C" in header file
{
.
}
Becomes:
SAFE_C_API_ARGS(const char *, func1, (int a, gpointer b), (a, b))
{
.
}
Which (essentially) expands to:
static const char *loc_func1(int a, gpointer b);
extern "C" const char *func1(int a, gpointer b)
{
ExceptFence exf;
return exf.forward_to(loc_func1, a, b);
}
static const char *loc_func1 (int a, gpointer b)
{
.
}
The essence of forward_to is the following:
template<typename Func, typename... Args>
auto forward_to(Func&& func, Args&&... args)
{
try {
m_except_data.exception_hit = true;
auto result = func(std::forward<Args>(args)...);
m_except_data.exception_hit = false;
return result;
}
catch (const std::exception& ex) {
m_except_data.exception_type = &typeid(ex);
m_except_data.exception_message = ex.what();
}
using ReturnType = std::invoke_result_t<Func, Args...>;
if constexpr (std::is_integral_v<ReturnType>) {
return static_cast<ReturnType>(m_exception_error_integer);
} else if constexpr (std::is_pointer_v<ReturnType>) {
return static_cast<ReturnType>(nullptr);
} else {
return ReturnType{};
}
}
This definition of forward_to() supports functions that return integer
types, pointer types, and structure types.
That appears to support most of what we need that I've seen.
There are 4 different SAFE_C_API macros to support all the combinations of
void args and void return types.
Anyway, if there are concerns about this approach, or request for more
details please let me know.
Thanks for your attention and support.
-russ
_______________________________________________
gnucash-devel mailing list
[email protected]
https://lists.gnucash.org/mailman/listinfo/gnucash-devel