aboutsummaryrefslogtreecommitdiff
path: root/odb/details
diff options
context:
space:
mode:
authorMichael Shepanski <michael@codesynthesis.com>2014-10-30 15:21:32 +1100
committerMichael Shepanski <michael@codesynthesis.com>2014-10-31 08:39:49 +1100
commit1f217e38f7507758da1d33d46e675e801621aa38 (patch)
treebad382ee315a820ec08bd2a83eaece12ac8169e3 /odb/details
parent31af5a488f2be9f4059e159492d4fe62f25a895a (diff)
Allow lambdas & std::functions as query factories with C++-98 builds of libodb
Diffstat (limited to 'odb/details')
-rw-r--r--odb/details/function-wrapper.hxx83
-rw-r--r--odb/details/function-wrapper.ixx47
-rw-r--r--odb/details/function-wrapper.txx87
3 files changed, 217 insertions, 0 deletions
diff --git a/odb/details/function-wrapper.hxx b/odb/details/function-wrapper.hxx
new file mode 100644
index 0000000..5615fca
--- /dev/null
+++ b/odb/details/function-wrapper.hxx
@@ -0,0 +1,83 @@
+// file : odb/details/function-wrapper.hxx
+// copyright : Copyright (c) 2009-2014 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_FUNCTION_WRAPPER_HXX
+#define ODB_DETAILS_FUNCTION_WRAPPER_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_CXX11
+
+#ifdef ODB_CXX11
+# include <functional> // std::function
+# include <type_traits> // std::enable_if, std::is_convertible
+#endif
+
+namespace odb
+{
+ namespace details
+ {
+ // Low-level 'callable object' wrapper similar to std::function but
+ // that works in both C++98 and 11. In particular, the call site can
+ // be compiled in C++98 and the registration site in C++11 and it
+ // will work.
+ //
+ template <typename F>
+ struct function_wrapper
+ {
+ ~function_wrapper ();
+
+ explicit
+ function_wrapper (F* = 0);
+
+#ifdef ODB_CXX11
+ typedef typename std::function<F> std_function_type;
+
+ // This overload accepts lambdas and std::functions, but when the
+ // argument is convertible to F*, then we disable it in favor of the
+ // other overload (above), which is more efficient.
+ //
+ // Subtlety alert: if you're thinking of changing this to accept a
+ // std::function<F> argument, stop. That creates an overload ambiguity
+ // when the actual parameter is a lambda, which is convertible to either
+ // std::function<F> or F*.
+ //
+ template <typename F1>
+ function_wrapper(F1,
+ typename std::enable_if<
+ !std::is_convertible<F1, F*>::value>::type* = 0);
+#endif
+
+ // Destructive copy construction and assignment (aka move). These
+ // should really only be called by containers when they need to
+ // reallocate the underlying buffer and move the elements.
+ //
+ function_wrapper (const function_wrapper<F>&);
+ function_wrapper&
+ operator= (const function_wrapper<F>&);
+
+ void swap (function_wrapper<F>&);
+
+ // Conversion to bool.
+ //
+ public:
+ typedef void (function_wrapper<F>::*bool_convertible) ();
+ void true_value () {}
+
+ operator bool_convertible () const;
+
+ public:
+ F* function;
+ void (*deleter) (const void*);
+ const void* std_function;
+ };
+ }
+}
+
+#include <odb/details/function-wrapper.ixx>
+#include <odb/details/function-wrapper.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_FUNCTION_WRAPPER_HXX
diff --git a/odb/details/function-wrapper.ixx b/odb/details/function-wrapper.ixx
new file mode 100644
index 0000000..58ede04
--- /dev/null
+++ b/odb/details/function-wrapper.ixx
@@ -0,0 +1,47 @@
+// file : odb/details/function-wrapper.ixx
+// copyright : Copyright (c) 2009-2014 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename F>
+ inline function_wrapper<F>::
+ ~function_wrapper ()
+ {
+ if (deleter != 0)
+ deleter (std_function);
+ }
+
+ template <typename F>
+ inline function_wrapper<F>::
+ function_wrapper (F* f)
+ : function (f), deleter (0), std_function (0)
+ {
+ }
+
+ template <typename F>
+ inline function_wrapper<F>::
+ function_wrapper (const function_wrapper<F>& x)
+ : function (0), deleter (0), std_function (0)
+ {
+ swap (const_cast<function_wrapper<F>&> (x));
+ }
+
+ template <typename F>
+ inline function_wrapper<F>& function_wrapper<F>::
+ operator= (const function_wrapper<F>& x)
+ {
+ swap (const_cast<function_wrapper<F>&> (x));
+ return *this;
+ }
+
+ template <typename F>
+ inline function_wrapper<F>::
+ operator bool_convertible () const
+ {
+ return function != 0 ? &function_wrapper<F>::true_value : 0;
+ }
+ }
+}
diff --git a/odb/details/function-wrapper.txx b/odb/details/function-wrapper.txx
new file mode 100644
index 0000000..70dcb0f
--- /dev/null
+++ b/odb/details/function-wrapper.txx
@@ -0,0 +1,87 @@
+// file : odb/details/function-wrapper.txx
+// copyright : Copyright (c) 2009-2014 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <utility> // std::swap, std::move
+
+namespace odb
+{
+ namespace details
+ {
+#ifdef ODB_CXX11
+ template <typename F>
+ struct caller_impl;
+
+#ifdef ODB_CXX11_VARIADIC_TEMPLATE
+ template <typename R, typename... A>
+ struct caller_impl<R (A...)>
+ {
+ static R
+ function (const void* f, A... a)
+ {
+ return (*static_cast<const std::function<R (A...)>*> (f)) (a...);
+ }
+ };
+#else
+ template <typename R, typename A1>
+ struct caller_impl<R (A1)>
+ {
+ static R
+ function (const void* f, A1 a1)
+ {
+ return (*static_cast<const std::function<R (A1)>*> (f)) (a1);
+ }
+ };
+
+ template <typename R, typename A1, typename A2>
+ struct caller_impl<R (A1, A2)>
+ {
+ static R
+ function (const void* f, A1 a1, A2 a2)
+ {
+ return (*static_cast<const std::function<R (A1, A2)>*> (f)) (a1, a2);
+ }
+ };
+#endif
+
+ template <typename F>
+ void
+ deleter_impl (const void* f)
+ {
+ delete static_cast<const std::function<F>*> (f);
+ }
+
+ template <typename F>
+ template <typename F1>
+ function_wrapper<F>::
+ function_wrapper (
+ F1 f,
+ typename std::enable_if<!std::is_convertible<F1, F*>::value>::type*)
+ {
+ std_function_type sf (std::move (f));
+
+ if (F* const* const f = sf.template target<F*> ())
+ {
+ function = *f;
+ deleter = 0;
+ std_function = 0;
+ }
+ else
+ {
+ function = reinterpret_cast<F*> (&caller_impl<F>::function);
+ deleter = &deleter_impl<F>;
+ std_function = new std_function_type (std::move (sf));
+ }
+ }
+#endif
+
+ template <typename F>
+ void function_wrapper<F>::
+ swap (function_wrapper<F>& x)
+ {
+ std::swap (function, x.function);
+ std::swap (deleter, x.deleter);
+ std::swap (std_function, x.std_function);
+ }
+ }
+}