summaryrefslogtreecommitdiff
path: root/libodb/odb/details
diff options
context:
space:
mode:
Diffstat (limited to 'libodb/odb/details')
-rw-r--r--libodb/odb/details/buffer.cxx35
-rw-r--r--libodb/odb/details/buffer.hxx92
-rw-r--r--libodb/odb/details/c-string.hxx28
-rw-r--r--libodb/odb/details/condition.cxx13
-rw-r--r--libodb/odb/details/condition.hxx68
-rw-r--r--libodb/odb/details/config-vc.h23
-rw-r--r--libodb/odb/details/config.h18
-rw-r--r--libodb/odb/details/config.hxx74
-rw-r--r--libodb/odb/details/exception.hxx21
-rw-r--r--libodb/odb/details/export.hxx46
-rw-r--r--libodb/odb/details/function-wrapper.hxx90
-rw-r--r--libodb/odb/details/function-wrapper.ixx49
-rw-r--r--libodb/odb/details/function-wrapper.txx89
-rw-r--r--libodb/odb/details/lock.cxx13
-rw-r--r--libodb/odb/details/lock.hxx59
-rw-r--r--libodb/odb/details/meta/answer.hxx30
-rw-r--r--libodb/odb/details/meta/class-p.hxx34
-rw-r--r--libodb/odb/details/meta/polymorphic-p.hxx57
-rw-r--r--libodb/odb/details/meta/remove-const-volatile.hxx31
-rw-r--r--libodb/odb/details/meta/remove-const.hxx32
-rw-r--r--libodb/odb/details/meta/remove-pointer.hxx32
-rw-r--r--libodb/odb/details/meta/remove-volatile.hxx32
-rw-r--r--libodb/odb/details/meta/static-assert.hxx32
-rw-r--r--libodb/odb/details/mutex.cxx13
-rw-r--r--libodb/odb/details/mutex.hxx53
-rw-r--r--libodb/odb/details/posix/condition.hxx47
-rw-r--r--libodb/odb/details/posix/condition.ixx38
-rw-r--r--libodb/odb/details/posix/exceptions.cxx22
-rw-r--r--libodb/odb/details/posix/exceptions.hxx38
-rw-r--r--libodb/odb/details/posix/mutex.hxx44
-rw-r--r--libodb/odb/details/posix/mutex.ixx37
-rw-r--r--libodb/odb/details/posix/thread.cxx44
-rw-r--r--libodb/odb/details/posix/thread.hxx41
-rw-r--r--libodb/odb/details/posix/thread.ixx29
-rw-r--r--libodb/odb/details/posix/tls.hxx106
-rw-r--r--libodb/odb/details/posix/tls.ixx20
-rw-r--r--libodb/odb/details/posix/tls.txx121
-rw-r--r--libodb/odb/details/shared-ptr-fwd.hxx24
-rw-r--r--libodb/odb/details/shared-ptr.hxx167
-rw-r--r--libodb/odb/details/shared-ptr/base.cxx83
-rw-r--r--libodb/odb/details/shared-ptr/base.hxx131
-rw-r--r--libodb/odb/details/shared-ptr/base.ixx119
-rw-r--r--libodb/odb/details/shared-ptr/base.txx198
-rw-r--r--libodb/odb/details/shared-ptr/counter-type.hxx23
-rw-r--r--libodb/odb/details/shared-ptr/exception.hxx31
-rw-r--r--libodb/odb/details/thread.cxx22
-rw-r--r--libodb/odb/details/thread.hxx65
-rw-r--r--libodb/odb/details/tls.hxx168
-rw-r--r--libodb/odb/details/transfer-ptr.hxx73
-rw-r--r--libodb/odb/details/type-info.hxx36
-rw-r--r--libodb/odb/details/unique-ptr.hxx95
-rw-r--r--libodb/odb/details/unused.hxx21
-rw-r--r--libodb/odb/details/win32/condition.cxx54
-rw-r--r--libodb/odb/details/win32/condition.hxx52
-rw-r--r--libodb/odb/details/win32/condition.ixx30
-rw-r--r--libodb/odb/details/win32/dll.cxx48
-rw-r--r--libodb/odb/details/win32/exceptions.cxx22
-rw-r--r--libodb/odb/details/win32/exceptions.hxx40
-rw-r--r--libodb/odb/details/win32/init.cxx41
-rw-r--r--libodb/odb/details/win32/init.hxx36
-rw-r--r--libodb/odb/details/win32/lock.hxx49
-rw-r--r--libodb/odb/details/win32/mutex.hxx43
-rw-r--r--libodb/odb/details/win32/mutex.ixx32
-rw-r--r--libodb/odb/details/win32/once-init.hxx23
-rw-r--r--libodb/odb/details/win32/once.cxx26
-rw-r--r--libodb/odb/details/win32/once.hxx50
-rw-r--r--libodb/odb/details/win32/once.ixx42
-rw-r--r--libodb/odb/details/win32/thread.cxx88
-rw-r--r--libodb/odb/details/win32/thread.hxx59
-rw-r--r--libodb/odb/details/win32/tls-init.hxx26
-rw-r--r--libodb/odb/details/win32/tls.cxx245
-rw-r--r--libodb/odb/details/win32/tls.hxx120
-rw-r--r--libodb/odb/details/win32/tls.ixx20
-rw-r--r--libodb/odb/details/win32/tls.txx94
-rw-r--r--libodb/odb/details/win32/windows.hxx33
-rw-r--r--libodb/odb/details/wrapper-p.hxx38
76 files changed, 4218 insertions, 0 deletions
diff --git a/libodb/odb/details/buffer.cxx b/libodb/odb/details/buffer.cxx
new file mode 100644
index 0000000..595329e
--- /dev/null
+++ b/libodb/odb/details/buffer.cxx
@@ -0,0 +1,35 @@
+// file : odb/details/buffer.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstring> // std::memcpy
+
+#include <odb/details/buffer.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ namespace details
+ {
+ void basic_buffer_base::
+ capacity (size_t c, size_t data_size)
+ {
+ if (c > capacity_)
+ {
+ size_t n (capacity_ * 2 > c ? capacity_ * 2 : c);
+ void* d (operator new (n));
+
+ if (data_ != 0)
+ {
+ if (data_size != 0)
+ memcpy (d, data_, data_size);
+
+ operator delete (data_);
+ }
+
+ data_ = d;
+ capacity_ = n;
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/buffer.hxx b/libodb/odb/details/buffer.hxx
new file mode 100644
index 0000000..558be9b
--- /dev/null
+++ b/libodb/odb/details/buffer.hxx
@@ -0,0 +1,92 @@
+// file : odb/details/buffer.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_BUFFER_DETAILS_HXX
+#define ODB_BUFFER_DETAILS_HXX
+
+#include <odb/pre.hxx>
+
+#include <new>
+#include <cstddef> // std::size_t
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT basic_buffer_base
+ {
+ public:
+ ~basic_buffer_base ()
+ {
+ if (data_ != 0)
+ operator delete (data_);
+ }
+
+ basic_buffer_base (std::size_t capacity)
+ : capacity_ (capacity)
+ {
+ data_ = capacity_ == 0 ? 0 : operator new (capacity_);
+ }
+
+ std::size_t
+ capacity () const
+ {
+ return capacity_;
+ }
+
+ void
+ capacity (std::size_t, std::size_t data_size = 0);
+
+ protected:
+ void* data_;
+ std::size_t capacity_;
+ };
+
+ template <typename T>
+ class basic_buffer: public basic_buffer_base
+ {
+ public:
+ basic_buffer (std::size_t capacity = 256)
+ : basic_buffer_base (capacity)
+ {
+ }
+
+ T*
+ data ()
+ {
+ return static_cast<T*> (data_);
+ }
+
+ const T*
+ data () const
+ {
+ return static_cast<T*> (data_);
+ }
+
+ // Note that strictly speaking the return type should be void* const*
+ // but that would make using this function too awkward since we often
+ // store the result as void*.
+ //
+ void**
+ data_ptr ()
+ {
+ return &data_;
+ }
+
+ const void* const*
+ data_ptr () const
+ {
+ return &data_;
+ }
+ };
+
+ typedef basic_buffer<char> buffer;
+ typedef basic_buffer<unsigned char> ubuffer;
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_BUFFER_DETAILS_HXX
diff --git a/libodb/odb/details/c-string.hxx b/libodb/odb/details/c-string.hxx
new file mode 100644
index 0000000..6ab1adc
--- /dev/null
+++ b/libodb/odb/details/c-string.hxx
@@ -0,0 +1,28 @@
+// file : odb/details/c-string.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_C_STRING_HXX
+#define ODB_DETAILS_C_STRING_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstring>
+
+namespace odb
+{
+ namespace details
+ {
+ struct c_string_comparator
+ {
+ bool
+ operator() (const char* x, const char* y) const
+ {
+ return std::strcmp (x, y) < 0;
+ }
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_C_STRING_HXX
diff --git a/libodb/odb/details/condition.cxx b/libodb/odb/details/condition.cxx
new file mode 100644
index 0000000..2c4cbdb
--- /dev/null
+++ b/libodb/odb/details/condition.cxx
@@ -0,0 +1,13 @@
+// file : odb/details/condition.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/condition.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // This otherwise unnecessary file is here to allow instantiation
+ // of inline functions for exporting.
+ }
+}
diff --git a/libodb/odb/details/condition.hxx b/libodb/odb/details/condition.hxx
new file mode 100644
index 0000000..10b6b4a
--- /dev/null
+++ b/libodb/odb/details/condition.hxx
@@ -0,0 +1,68 @@
+// file : odb/details/condition.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_CONDITION_HXX
+#define ODB_DETAILS_CONDITION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx>
+
+#ifdef ODB_THREADS_NONE
+
+namespace odb
+{
+ namespace details
+ {
+ class mutex;
+ class lock;
+
+ class condition
+ {
+ public:
+ condition (mutex&) {}
+
+ void
+ signal () {}
+
+ void
+ wait (lock&) {}
+
+ private:
+ condition (const condition&);
+ condition& operator= (const condition&);
+ };
+ }
+}
+
+#elif defined(ODB_THREADS_CXX11)
+# include <condition_variable>
+# include <odb/details/mutex.hxx>
+# include <odb/details/lock.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class condition: public std::condition_variable
+ {
+ public:
+ condition (mutex&) {}
+
+ void
+ signal () {notify_one ();}
+ };
+ }
+}
+
+#elif defined(ODB_THREADS_POSIX)
+#include <odb/details/posix/condition.hxx>
+#elif defined(ODB_THREADS_WIN32)
+#include <odb/details/win32/condition.hxx>
+#else
+# error unknown threading model
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_CONDITION_HXX
diff --git a/libodb/odb/details/config-vc.h b/libodb/odb/details/config-vc.h
new file mode 100644
index 0000000..7c4def0
--- /dev/null
+++ b/libodb/odb/details/config-vc.h
@@ -0,0 +1,23 @@
+/* file : odb/details/config-vc.h
+ * license : GNU GPL v2; see accompanying LICENSE file
+ */
+
+/* Configuration file for Windows/VC++ for the build2 build.
+ *
+ * Note that currently we only support ODB_THREADS_NONE and ODB_THREADS_CXX11
+ * but could also support the _WIN32 variant with a bit of effort.
+ *
+ */
+
+#ifndef ODB_DETAILS_CONFIG_VC_H
+#define ODB_DETAILS_CONFIG_VC_H
+
+#ifndef ODB_THREADS_NONE
+# if _MSC_VER >= 1900
+# define ODB_THREADS_CXX11
+# else
+# error Unsupoprted MSVC version (no thread_local)
+# endif
+#endif
+
+#endif /* ODB_DETAILS_CONFIG_VC_H */
diff --git a/libodb/odb/details/config.h b/libodb/odb/details/config.h
new file mode 100644
index 0000000..4ad9a8d
--- /dev/null
+++ b/libodb/odb/details/config.h
@@ -0,0 +1,18 @@
+/* file : odb/details/config.h
+ * license : GNU GPL v2; see accompanying LICENSE file
+ */
+
+/* Static configuration file for build2 build.
+ *
+ * Note that currently we only support ODB_THREADS_NONE and ODB_THREADS_CXX11
+ * but could also support the _POSIX and _WIN32 variants with a bit of effort.
+ */
+
+#ifndef ODB_DETAILS_CONFIG_H
+#define ODB_DETAILS_CONFIG_H
+
+#ifndef ODB_THREADS_NONE
+# define ODB_THREADS_CXX11
+#endif
+
+#endif /* ODB_DETAILS_CONFIG_H */
diff --git a/libodb/odb/details/config.hxx b/libodb/odb/details/config.hxx
new file mode 100644
index 0000000..3168109
--- /dev/null
+++ b/libodb/odb/details/config.hxx
@@ -0,0 +1,74 @@
+// file : odb/details/config.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_CONFIG_HXX
+#define ODB_DETAILS_CONFIG_HXX
+
+// no pre
+
+// C++11 support.
+//
+#ifdef _MSC_VER
+# if _MSC_VER >= 1600 // VC++10 and later have C++11 always enabled.
+# define ODB_CXX11
+# define ODB_CXX11_NULLPTR
+# if _MSC_VER >= 1700
+# define ODB_CXX11_ENUM
+# if _MSC_VER >= 1800
+# define ODB_CXX11_DELETED_FUNCTION
+# define ODB_CXX11_EXPLICIT_CONVERSION_OPERATOR
+# define ODB_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGUMENT
+# define ODB_CXX11_VARIADIC_TEMPLATE
+# define ODB_CXX11_INITIALIZER_LIST
+# if _MSC_VER >= 1900
+# define ODB_CXX11_NOEXCEPT
+# endif
+# endif
+# endif
+# endif
+#else
+# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+# define ODB_CXX11
+# ifdef __clang__ // Pretends to be a really old __GNUC__ on some platforms.
+# define ODB_CXX11_NULLPTR
+# define ODB_CXX11_NOEXCEPT
+# elif defined(__GNUC__)
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
+# define ODB_CXX11_NULLPTR
+# define ODB_CXX11_NOEXCEPT
+# endif
+# else
+# define ODB_CXX11_NULLPTR
+# define ODB_CXX11_NOEXCEPT
+# endif
+# define ODB_CXX11_DELETED_FUNCTION
+# define ODB_CXX11_EXPLICIT_CONVERSION_OPERATOR
+# define ODB_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGUMENT
+# define ODB_CXX11_VARIADIC_TEMPLATE
+# define ODB_CXX11_INITIALIZER_LIST
+# define ODB_CXX11_ENUM // GCC 4.4 (forward -- 4.6), Clang 2.9 (3.1).
+# endif
+#endif
+
+#ifdef ODB_CXX11_NOEXCEPT
+# define ODB_NOTHROW_NOEXCEPT noexcept
+#else
+# define ODB_NOTHROW_NOEXCEPT throw()
+#endif
+
+// Once we drop support for C++98, we can probably get rid of config.h except
+// for the autotools case by fixing ODB_THREADS_CXX11 (and perhaps supporting
+// the ODB_THREADS_NONE case via a "global" (command line) define).
+//
+#ifdef ODB_COMPILER
+# define ODB_THREADS_NONE
+# define LIBODB_STATIC
+#elif defined(_MSC_VER)
+# include <odb/details/config-vc.h>
+#else
+# include <odb/details/config.h>
+#endif
+
+// no post
+
+#endif // ODB_DETAILS_CONFIG_HXX
diff --git a/libodb/odb/details/exception.hxx b/libodb/odb/details/exception.hxx
new file mode 100644
index 0000000..ab838e1
--- /dev/null
+++ b/libodb/odb/details/exception.hxx
@@ -0,0 +1,21 @@
+// file : odb/details/exception.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_EXCEPTION_HXX
+#define ODB_DETAILS_EXCEPTION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/exception.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct exception: odb::exception {};
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_EXCEPTION_HXX
diff --git a/libodb/odb/details/export.hxx b/libodb/odb/details/export.hxx
new file mode 100644
index 0000000..2ddc104
--- /dev/null
+++ b/libodb/odb/details/export.hxx
@@ -0,0 +1,46 @@
+// file : odb/details/export.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_EXPORT_HXX
+#define ODB_DETAILS_EXPORT_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // LIBODB_STATIC if ODB_COMPILER
+
+// Normally we don't export class templates (but do complete specializations),
+// inline functions, and classes with only inline member functions. Exporting
+// classes that inherit from non-exported/imported bases (e.g., std::string)
+// will end up badly. The only known workarounds are to not inherit or to not
+// export. Also, MinGW GCC doesn't like seeing non-exported function being
+// used before their inline definition. The workaround is to reorder code. In
+// the end it's all trial and error.
+
+#if defined(LIBODB_STATIC) // Using static.
+# define LIBODB_EXPORT
+#elif defined(LIBODB_STATIC_BUILD) // Building static.
+# define LIBODB_EXPORT
+#elif defined(LIBODB_SHARED) // Using shared.
+# ifdef _WIN32
+# define LIBODB_EXPORT __declspec(dllimport)
+# else
+# define LIBODB_EXPORT
+# endif
+#elif defined(LIBODB_SHARED_BUILD) // Building shared.
+# ifdef _WIN32
+# define LIBODB_EXPORT __declspec(dllexport)
+# else
+# define LIBODB_EXPORT
+# endif
+#else
+// If none of the above macros are defined, then we assume we are being used
+// by some third-party build system that cannot/doesn't signal the library
+// type. Note that this fallback works for both static and shared but in case
+// of shared will be sub-optimal compared to having dllimport.
+//
+# define LIBODB_EXPORT // Using static or shared.
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_EXPORT_HXX
diff --git a/libodb/odb/details/function-wrapper.hxx b/libodb/odb/details/function-wrapper.hxx
new file mode 100644
index 0000000..418a625
--- /dev/null
+++ b/libodb/odb/details/function-wrapper.hxx
@@ -0,0 +1,90 @@
+// file : odb/details/function-wrapper.hxx
+// 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>&);
+
+ // Cleanly cast to an incompatible function type.
+ //
+ template <typename R> R
+ cast () const;
+
+ // Conversion to bool.
+ //
+ public:
+ typedef void (function_wrapper<F>::*bool_convertible) ();
+ void true_value () {}
+
+ operator bool_convertible () const
+ {
+ return function != 0 ? &function_wrapper<F>::true_value : 0;
+ }
+
+ 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/libodb/odb/details/function-wrapper.ixx b/libodb/odb/details/function-wrapper.ixx
new file mode 100644
index 0000000..5b83b96
--- /dev/null
+++ b/libodb/odb/details/function-wrapper.ixx
@@ -0,0 +1,49 @@
+// file : odb/details/function-wrapper.ixx
+// 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>
+ template <typename R>
+ inline R function_wrapper<F>::
+ cast () const
+ {
+ union { F* f; R r; } r;
+ r.f = function;
+ return r.r;
+ }
+ }
+}
diff --git a/libodb/odb/details/function-wrapper.txx b/libodb/odb/details/function-wrapper.txx
new file mode 100644
index 0000000..db73e8d
--- /dev/null
+++ b/libodb/odb/details/function-wrapper.txx
@@ -0,0 +1,89 @@
+// file : odb/details/function-wrapper.txx
+// 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_wrapper<decltype (caller_impl<F>::function)> fw (
+ &caller_impl<F>::function);
+
+ function = fw.template cast<F*> ();
+ 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);
+ }
+ }
+}
diff --git a/libodb/odb/details/lock.cxx b/libodb/odb/details/lock.cxx
new file mode 100644
index 0000000..f474bf5
--- /dev/null
+++ b/libodb/odb/details/lock.cxx
@@ -0,0 +1,13 @@
+// file : odb/details/lock.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/lock.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // This otherwise unnecessary file is here to allow instantiation
+ // of inline functions for exporting.
+ }
+}
diff --git a/libodb/odb/details/lock.hxx b/libodb/odb/details/lock.hxx
new file mode 100644
index 0000000..0c54f03
--- /dev/null
+++ b/libodb/odb/details/lock.hxx
@@ -0,0 +1,59 @@
+// file : odb/details/lock.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_LOCK_HXX
+#define ODB_DETAILS_LOCK_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/mutex.hxx>
+
+#ifdef ODB_THREADS_CXX11
+# include <mutex>
+namespace odb
+{
+ namespace details
+ {
+ using lock = std::unique_lock<mutex>;
+ }
+}
+#else
+namespace odb
+{
+ namespace details
+ {
+ class lock
+ {
+ public:
+ lock (mutex& m)
+ : mutex_ (&m)
+ {
+ mutex_->lock ();
+ }
+
+ ~lock ()
+ {
+ if (mutex_ != 0)
+ mutex_->unlock ();
+ }
+
+ void
+ unlock ()
+ {
+ if (mutex_ != 0)
+ {
+ mutex_->unlock ();
+ mutex_ = 0;
+ }
+ }
+
+ private:
+ mutex* mutex_;
+ };
+ }
+}
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_LOCK_HXX
diff --git a/libodb/odb/details/meta/answer.hxx b/libodb/odb/details/meta/answer.hxx
new file mode 100644
index 0000000..f15dc43
--- /dev/null
+++ b/libodb/odb/details/meta/answer.hxx
@@ -0,0 +1,30 @@
+// file : odb/details/meta/answer.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_ANSWER_HXX
+#define ODB_DETAILS_META_ANSWER_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ struct yes
+ {
+ char filling;
+ };
+
+ struct no
+ {
+ char filling[2];
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_ANSWER_HXX
diff --git a/libodb/odb/details/meta/class-p.hxx b/libodb/odb/details/meta/class-p.hxx
new file mode 100644
index 0000000..bddb452
--- /dev/null
+++ b/libodb/odb/details/meta/class-p.hxx
@@ -0,0 +1,34 @@
+// file : odb/details/meta/class-p.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_CLASS_HXX
+#define ODB_DETAILS_META_CLASS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/meta/answer.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ // g++ cannot have these inside class_p.
+ //
+ template <typename X> no class_p_test (...);
+ template <typename X> yes class_p_test (void (X::*) ());
+
+ template <typename X>
+ struct class_p
+ {
+ static const bool result =
+ sizeof (class_p_test<X> (0)) == sizeof (yes);
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_CLASS_HXX
diff --git a/libodb/odb/details/meta/polymorphic-p.hxx b/libodb/odb/details/meta/polymorphic-p.hxx
new file mode 100644
index 0000000..10fef6a
--- /dev/null
+++ b/libodb/odb/details/meta/polymorphic-p.hxx
@@ -0,0 +1,57 @@
+// file : odb/details/meta/polymorphic-p.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_POLYMORPHIC_HXX
+#define ODB_DETAILS_META_POLYMORPHIC_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/meta/class-p.hxx>
+#include <odb/details/meta/remove-const-volatile.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <typename CVX>
+ struct polymorphic_p
+ {
+ typedef typename remove_const_volatile<CVX>::result X;
+
+ template <typename Y, bool C>
+ struct impl
+ {
+ static const bool result = false;
+ };
+
+ template <typename Y>
+ struct impl<Y, true>
+ {
+ struct t1: Y
+ {
+ t1 ();
+ };
+
+ struct t2: Y
+ {
+ t2 ();
+
+ virtual
+ ~t2 () ODB_NOTHROW_NOEXCEPT;
+ };
+
+ static const bool result = sizeof (t1) == sizeof (t2);
+ };
+
+ static const bool result = impl<X, class_p<X>::result>::result;
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_POLYMORPHIC_HXX
diff --git a/libodb/odb/details/meta/remove-const-volatile.hxx b/libodb/odb/details/meta/remove-const-volatile.hxx
new file mode 100644
index 0000000..910ec35
--- /dev/null
+++ b/libodb/odb/details/meta/remove-const-volatile.hxx
@@ -0,0 +1,31 @@
+// file : odb/details/meta/remove-const-volatile.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_REMOVE_CONST_VOLATILE_HXX
+#define ODB_DETAILS_META_REMOVE_CONST_VOLATILE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/meta/remove-const.hxx>
+#include <odb/details/meta/remove-volatile.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <typename X>
+ struct remove_const_volatile
+ {
+ typedef
+ typename remove_volatile<typename remove_const<X>::result>::result
+ result;
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_REMOVE_CONST_VOLATILE_HXX
diff --git a/libodb/odb/details/meta/remove-const.hxx b/libodb/odb/details/meta/remove-const.hxx
new file mode 100644
index 0000000..4a92ed3
--- /dev/null
+++ b/libodb/odb/details/meta/remove-const.hxx
@@ -0,0 +1,32 @@
+// file : odb/details/meta/remove-const.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_REMOVE_CONST_HXX
+#define ODB_DETAILS_META_REMOVE_CONST_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <typename X>
+ struct remove_const
+ {
+ typedef X result;
+ };
+
+ template <typename X>
+ struct remove_const<const X>
+ {
+ typedef X result;
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_REMOVE_CONST_HXX
diff --git a/libodb/odb/details/meta/remove-pointer.hxx b/libodb/odb/details/meta/remove-pointer.hxx
new file mode 100644
index 0000000..9963fd7
--- /dev/null
+++ b/libodb/odb/details/meta/remove-pointer.hxx
@@ -0,0 +1,32 @@
+// file : odb/details/meta/remove-pointer.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_REMOVE_POINTER_HXX
+#define ODB_DETAILS_META_REMOVE_POINTER_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <typename X>
+ struct remove_pointer
+ {
+ typedef X result;
+ };
+
+ template <typename X>
+ struct remove_pointer<X*>
+ {
+ typedef X result;
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_REMOVE_POINTER_HXX
diff --git a/libodb/odb/details/meta/remove-volatile.hxx b/libodb/odb/details/meta/remove-volatile.hxx
new file mode 100644
index 0000000..877e532
--- /dev/null
+++ b/libodb/odb/details/meta/remove-volatile.hxx
@@ -0,0 +1,32 @@
+// file : odb/details/meta/remove-volatile.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_REMOVE_VOLATILE_HXX
+#define ODB_DETAILS_META_REMOVE_VOLATILE_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <typename X>
+ struct remove_volatile
+ {
+ typedef X result;
+ };
+
+ template <typename X>
+ struct remove_volatile<volatile X>
+ {
+ typedef X result;
+ };
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_REMOVE_VOLATILE_HXX
diff --git a/libodb/odb/details/meta/static-assert.hxx b/libodb/odb/details/meta/static-assert.hxx
new file mode 100644
index 0000000..a2cc81b
--- /dev/null
+++ b/libodb/odb/details/meta/static-assert.hxx
@@ -0,0 +1,32 @@
+// file : odb/details/meta/static-assert.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_META_STATIC_ASSERT_HXX
+#define ODB_DETAILS_META_STATIC_ASSERT_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_CXX11
+
+#ifndef ODB_CXX11
+
+namespace odb
+{
+ namespace details
+ {
+ namespace meta
+ {
+ template <bool>
+ struct static_assert_test;
+
+ template <>
+ struct static_assert_test<true> {};
+ }
+ }
+}
+
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_META_STATIC_ASSERT_HXX
diff --git a/libodb/odb/details/mutex.cxx b/libodb/odb/details/mutex.cxx
new file mode 100644
index 0000000..df367d8
--- /dev/null
+++ b/libodb/odb/details/mutex.cxx
@@ -0,0 +1,13 @@
+// file : odb/details/mutex.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // This otherwise unnecessary file is here to allow instantiation
+ // of inline functions for exporting.
+ }
+}
diff --git a/libodb/odb/details/mutex.hxx b/libodb/odb/details/mutex.hxx
new file mode 100644
index 0000000..df12013
--- /dev/null
+++ b/libodb/odb/details/mutex.hxx
@@ -0,0 +1,53 @@
+// file : odb/details/mutex.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_MUTEX_HXX
+#define ODB_DETAILS_MUTEX_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx>
+
+#ifdef ODB_THREADS_NONE
+
+namespace odb
+{
+ namespace details
+ {
+ class mutex
+ {
+ public:
+ mutex () {}
+
+ void
+ lock () {}
+
+ void
+ unlock () {}
+
+ private:
+ mutex (const mutex&);
+ mutex& operator= (const mutex&);
+ };
+ }
+}
+#elif defined(ODB_THREADS_CXX11)
+# include <mutex>
+namespace odb
+{
+ namespace details
+ {
+ using std::mutex;
+ }
+}
+#elif defined(ODB_THREADS_POSIX)
+#include <odb/details/posix/mutex.hxx>
+#elif defined(ODB_THREADS_WIN32)
+#include <odb/details/win32/mutex.hxx>
+#else
+# error unknown threading model
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_MUTEX_HXX
diff --git a/libodb/odb/details/posix/condition.hxx b/libodb/odb/details/posix/condition.hxx
new file mode 100644
index 0000000..4f7c42a
--- /dev/null
+++ b/libodb/odb/details/posix/condition.hxx
@@ -0,0 +1,47 @@
+// file : odb/details/posix/condition.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_POSIX_CONDITION_HXX
+#define ODB_DETAILS_POSIX_CONDITION_HXX
+
+#include <odb/pre.hxx>
+
+#include <pthread.h>
+
+#include <odb/details/export.hxx>
+#include <odb/details/posix/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class lock;
+
+ class LIBODB_EXPORT condition
+ {
+ public:
+ ~condition ();
+ condition (mutex&);
+
+ void
+ signal ();
+
+ void
+ wait (lock&);
+
+ private:
+ condition (const condition&);
+ condition& operator= (const condition&);
+
+ private:
+ mutex& mutex_;
+ pthread_cond_t cond_;
+ };
+ }
+}
+
+#include <odb/details/posix/condition.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_POSIX_CONDITION_HXX
diff --git a/libodb/odb/details/posix/condition.ixx b/libodb/odb/details/posix/condition.ixx
new file mode 100644
index 0000000..9b68d9f
--- /dev/null
+++ b/libodb/odb/details/posix/condition.ixx
@@ -0,0 +1,38 @@
+// file : odb/details/posix/condition.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/posix/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline condition::
+ ~condition ()
+ {
+ pthread_cond_destroy (&cond_);
+ }
+
+ inline condition::
+ condition (mutex& mutex)
+ : mutex_ (mutex)
+ {
+ if (int e = pthread_cond_init (&cond_, 0))
+ throw posix_exception (e);
+ }
+
+ inline void condition::
+ signal ()
+ {
+ if (int e = pthread_cond_signal (&cond_))
+ throw posix_exception (e);
+ }
+
+ inline void condition::
+ wait (lock&)
+ {
+ if (int e = pthread_cond_wait (&cond_, &mutex_.mutex_))
+ throw posix_exception (e);
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/exceptions.cxx b/libodb/odb/details/posix/exceptions.cxx
new file mode 100644
index 0000000..c346655
--- /dev/null
+++ b/libodb/odb/details/posix/exceptions.cxx
@@ -0,0 +1,22 @@
+// file : odb/details/posix/exceptions.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/posix/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ const char* posix_exception::
+ what () const ODB_NOTHROW_NOEXCEPT
+ {
+ return "POSIX API error";
+ }
+
+ posix_exception* posix_exception::
+ clone () const
+ {
+ return new posix_exception (*this);
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/exceptions.hxx b/libodb/odb/details/posix/exceptions.hxx
new file mode 100644
index 0000000..aff33b6
--- /dev/null
+++ b/libodb/odb/details/posix/exceptions.hxx
@@ -0,0 +1,38 @@
+// file : odb/details/posix/exceptions.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_POSIX_EXCEPTIONS_HXX
+#define ODB_DETAILS_POSIX_EXCEPTIONS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/export.hxx>
+#include <odb/details/exception.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT posix_exception: details::exception
+ {
+ posix_exception (int code) : code_ (code) {}
+
+ int
+ code () const {return code_;}
+
+ virtual const char*
+ what () const ODB_NOTHROW_NOEXCEPT;
+
+ virtual posix_exception*
+ clone () const;
+
+ private:
+ int code_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_POSIX_EXCEPTIONS_HXX
diff --git a/libodb/odb/details/posix/mutex.hxx b/libodb/odb/details/posix/mutex.hxx
new file mode 100644
index 0000000..0cb94db
--- /dev/null
+++ b/libodb/odb/details/posix/mutex.hxx
@@ -0,0 +1,44 @@
+// file : odb/details/posix/mutex.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_POSIX_MUTEX_HXX
+#define ODB_DETAILS_POSIX_MUTEX_HXX
+
+#include <odb/pre.hxx>
+
+#include <pthread.h>
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT mutex
+ {
+ public:
+ ~mutex ();
+ mutex ();
+
+ void
+ lock ();
+
+ void
+ unlock ();
+
+ private:
+ mutex (const mutex&);
+ mutex& operator= (const mutex&);
+
+ private:
+ friend class condition;
+ pthread_mutex_t mutex_;
+ };
+ }
+}
+
+#include <odb/details/posix/mutex.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_POSIX_MUTEX_HXX
diff --git a/libodb/odb/details/posix/mutex.ixx b/libodb/odb/details/posix/mutex.ixx
new file mode 100644
index 0000000..ee73d09
--- /dev/null
+++ b/libodb/odb/details/posix/mutex.ixx
@@ -0,0 +1,37 @@
+// file : odb/details/posix/mutex.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/posix/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline mutex::
+ ~mutex ()
+ {
+ pthread_mutex_destroy (&mutex_);
+ }
+
+ inline mutex::
+ mutex ()
+ {
+ if (int e = pthread_mutex_init (&mutex_, 0))
+ throw posix_exception (e);
+ }
+
+ inline void mutex::
+ lock ()
+ {
+ if (int e = pthread_mutex_lock (&mutex_))
+ throw posix_exception (e);
+ }
+
+ inline void mutex::
+ unlock ()
+ {
+ if (int e = pthread_mutex_unlock (&mutex_))
+ throw posix_exception (e);
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/thread.cxx b/libodb/odb/details/posix/thread.cxx
new file mode 100644
index 0000000..045f32a
--- /dev/null
+++ b/libodb/odb/details/posix/thread.cxx
@@ -0,0 +1,44 @@
+// file : odb/details/posix/thread.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/posix/thread.hxx>
+#include <odb/details/posix/exceptions.hxx>
+
+typedef void* (*thread_func) (void*);
+
+struct thread_data
+{
+ thread_func func;
+ void* arg;
+};
+
+extern "C" void*
+odb_thread_thunk (void* arg)
+{
+ thread_data* data (static_cast<thread_data*> (arg));
+ thread_func func = data->func;
+ arg = data->arg;
+ delete data;
+ return func (arg);
+}
+
+namespace odb
+{
+ namespace details
+ {
+ thread::
+ thread (void* (*func) (void*), void* arg)
+ : detached_ (false)
+ {
+ unique_ptr<thread_data> data (new thread_data);
+ data->func = func;
+ data->arg = arg;
+
+ if (int e = pthread_create (&id_, 0, &odb_thread_thunk, data.get ()))
+ throw posix_exception (e);
+
+ data.release (); // Thread thunk will free this.
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/thread.hxx b/libodb/odb/details/posix/thread.hxx
new file mode 100644
index 0000000..f0d29a7
--- /dev/null
+++ b/libodb/odb/details/posix/thread.hxx
@@ -0,0 +1,41 @@
+// file : odb/details/posix/thread.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_POSIX_THREAD_HXX
+#define ODB_DETAILS_POSIX_THREAD_HXX
+
+#include <odb/pre.hxx>
+
+#include <pthread.h>
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT thread
+ {
+ public:
+ ~thread ();
+ thread (void* (*thread_func) (void*), void* arg = 0);
+
+ void*
+ join ();
+
+ private:
+ thread (const thread&);
+ thread& operator= (const thread&);
+
+ private:
+ bool detached_;
+ pthread_t id_;
+ };
+ }
+}
+
+#include <odb/details/posix/thread.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_POSIX_THREAD_HXX
diff --git a/libodb/odb/details/posix/thread.ixx b/libodb/odb/details/posix/thread.ixx
new file mode 100644
index 0000000..6576101
--- /dev/null
+++ b/libodb/odb/details/posix/thread.ixx
@@ -0,0 +1,29 @@
+// file : odb/details/posix/thread.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/posix/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline thread::
+ ~thread ()
+ {
+ if (!detached_)
+ pthread_detach (id_);
+ }
+
+ inline void* thread::
+ join ()
+ {
+ void* r;
+
+ if (int e = pthread_join (id_, &r))
+ throw posix_exception (e);
+
+ detached_ = true;
+ return r;
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/tls.hxx b/libodb/odb/details/posix/tls.hxx
new file mode 100644
index 0000000..e868819
--- /dev/null
+++ b/libodb/odb/details/posix/tls.hxx
@@ -0,0 +1,106 @@
+// file : odb/details/posix/tls.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_POSIX_TLS_HXX
+#define ODB_DETAILS_POSIX_TLS_HXX
+
+#include <odb/pre.hxx>
+
+#include <pthread.h>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ class tls
+ {
+ public:
+ tls ();
+
+ T&
+ get () const;
+
+ void
+ free ();
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ static void
+ destructor (void*);
+
+ private:
+ static int error_;
+ static pthread_once_t once_;
+ static pthread_key_t key_;
+ };
+
+ template <typename T>
+ class tls<T*>
+ {
+ public:
+ tls ();
+
+ T*
+ get () const;
+
+ void
+ set (T* p);
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ private:
+ static int error_;
+ static pthread_once_t once_;
+ static pthread_key_t key_;
+ };
+
+ template <typename T>
+ inline T&
+ tls_get (const tls<T>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T>
+ inline void
+ tls_free (tls<T>& t)
+ {
+ t.free ();
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (const tls<T*>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (tls<T*>& t, T1* p1)
+ {
+ T* p (p1);
+ t.set (p);
+ }
+ }
+}
+
+#include <odb/details/posix/tls.ixx>
+#include <odb/details/posix/tls.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_POSIX_TLS_HXX
diff --git a/libodb/odb/details/posix/tls.ixx b/libodb/odb/details/posix/tls.ixx
new file mode 100644
index 0000000..7acc173
--- /dev/null
+++ b/libodb/odb/details/posix/tls.ixx
@@ -0,0 +1,20 @@
+// file : odb/details/posix/tls.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline tls<T>::
+ tls ()
+ {
+ }
+
+ template <typename T>
+ inline tls<T*>::
+ tls ()
+ {
+ }
+ }
+}
diff --git a/libodb/odb/details/posix/tls.txx b/libodb/odb/details/posix/tls.txx
new file mode 100644
index 0000000..e4c5b8f
--- /dev/null
+++ b/libodb/odb/details/posix/tls.txx
@@ -0,0 +1,121 @@
+// file : odb/details/posix/tls.txx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/posix/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // tls<T>
+ //
+
+ template <typename T>
+ int tls<T>::error_ = 0;
+
+ template <typename T>
+ pthread_once_t tls<T>::once_ = PTHREAD_ONCE_INIT;
+
+ template <typename T>
+ pthread_key_t tls<T>::key_;
+
+ template <typename T>
+ T& tls<T>::
+ get () const
+ {
+ int e (pthread_once (&once_, key_init));
+
+ if (e != 0 || error_ != 0)
+ throw posix_exception (e ? e : error_);
+
+ if (void* v = pthread_getspecific (key_))
+ return *static_cast<T*> (v);
+
+ unique_ptr<T> p (new T);
+
+ if ((e = pthread_setspecific (key_, p.get ())))
+ throw posix_exception (e);
+
+ T& r (*p);
+ p.release ();
+ return r;
+ }
+
+ template <typename T>
+ void tls<T>::
+ free ()
+ {
+ int e (pthread_once (&once_, key_init));
+
+ if (e != 0 || error_ != 0)
+ throw posix_exception (e ? e : error_);
+
+ if (void* v = pthread_getspecific (key_))
+ {
+ if ((e = pthread_setspecific (key_, 0)))
+ throw posix_exception (e);
+
+ delete static_cast<T*> (v);
+ }
+ }
+
+ template <typename T>
+ void tls<T>::
+ key_init ()
+ {
+ error_ = pthread_key_create (&key_, destructor);
+ }
+
+ template <typename T>
+ void tls<T>::
+ destructor (void* v)
+ {
+ delete static_cast<T*> (v);
+ }
+
+ // tls<T*>
+ //
+
+ template <typename T>
+ int tls<T*>::error_ = 0;
+
+ template <typename T>
+ pthread_once_t tls<T*>::once_ = PTHREAD_ONCE_INIT;
+
+ template <typename T>
+ pthread_key_t tls<T*>::key_;
+
+ template <typename T>
+ T* tls<T*>::
+ get () const
+ {
+ int e (pthread_once (&once_, key_init));
+
+ if (e != 0 || error_ != 0)
+ throw posix_exception (e ? e : error_);
+
+ return static_cast<T*> (pthread_getspecific (key_));
+ }
+
+ template <typename T>
+ void tls<T*>::
+ set (T* p)
+ {
+ int e (pthread_once (&once_, key_init));
+
+ if (e != 0 || error_ != 0)
+ throw posix_exception (e ? e : error_);
+
+ if ((e = pthread_setspecific (key_, p)))
+ throw posix_exception (e);
+ }
+
+ template <typename T>
+ void tls<T*>::
+ key_init ()
+ {
+ error_ = pthread_key_create (&key_, 0);
+ }
+ }
+}
diff --git a/libodb/odb/details/shared-ptr-fwd.hxx b/libodb/odb/details/shared-ptr-fwd.hxx
new file mode 100644
index 0000000..73377b9
--- /dev/null
+++ b/libodb/odb/details/shared-ptr-fwd.hxx
@@ -0,0 +1,24 @@
+// file : odb/details/shared-ptr-fwd.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_FWD_HXX
+#define ODB_DETAILS_SHARED_PTR_FWD_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/shared-ptr/counter-type.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename X>
+ class shared_ptr;
+
+ class shared_base;
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_FWD_HXX
diff --git a/libodb/odb/details/shared-ptr.hxx b/libodb/odb/details/shared-ptr.hxx
new file mode 100644
index 0000000..5a1e842
--- /dev/null
+++ b/libodb/odb/details/shared-ptr.hxx
@@ -0,0 +1,167 @@
+// file : odb/details/shared-ptr.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_HXX
+#define ODB_DETAILS_SHARED_PTR_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/shared-ptr-fwd.hxx>
+#include <odb/details/shared-ptr/base.hxx>
+#include <odb/details/shared-ptr/exception.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename X>
+ class shared_ptr:
+ private bits::counter_ops<typename bits::counter_type<X>::r, X>
+ {
+ typedef bits::counter_ops<typename bits::counter_type<X>::r, X> base;
+
+ public:
+ ~shared_ptr ()
+ {
+ if (x_ != 0)
+ base::dec (x_);
+ }
+
+ explicit
+ shared_ptr (X* x = 0)
+ : base (x), x_ (x)
+ {
+ }
+
+ shared_ptr (const shared_ptr& x)
+ : base (x), x_ (x.x_)
+ {
+ if (x_ != 0)
+ base::inc (x_);
+ }
+
+ template <typename Y>
+ shared_ptr (const shared_ptr<Y>& x)
+ : base (x), x_ (x.x_)
+ {
+ if (x_ != 0)
+ base::inc (x_);
+ }
+
+ shared_ptr&
+ operator= (const shared_ptr& x)
+ {
+ if (x_ != x.x_)
+ {
+ if (x_ != 0)
+ base::dec (x_);
+
+ static_cast<base&> (*this) = x;
+ x_ = x.x_;
+
+ if (x_ != 0)
+ base::inc (x_);
+ }
+
+ return *this;
+ }
+
+ template <typename Y>
+ shared_ptr&
+ operator= (const shared_ptr<Y>& x)
+ {
+ if (x_ != x.x_)
+ {
+ if (x_ != 0)
+ base::dec (x_);
+
+ static_cast<base&> (*this) = x;
+ x_ = x.x_;
+
+ if (x_ != 0)
+ base::inc (x_);
+ }
+
+ return *this;
+ }
+
+ public:
+ X*
+ operator-> () const
+ {
+ return x_;
+ }
+
+ X&
+ operator* () const
+ {
+ return *x_;
+ }
+
+ // Conversion to bool.
+ //
+ typedef void (shared_ptr::*boolean_convertible)();
+ void true_value () {}
+
+ operator boolean_convertible () const
+ {
+ return x_ ? &shared_ptr<X>::true_value : 0;
+ }
+
+ public:
+ X*
+ get () const
+ {
+ return x_;
+ }
+
+ X*
+ release ()
+ {
+ X* r (x_);
+ x_ = 0;
+ return r;
+ }
+
+ void
+ reset (X* x = 0)
+ {
+ if (x_ != 0)
+ base::dec (x_);
+
+ base::reset (x);
+ x_ = x;
+ }
+
+ std::size_t
+ count () const
+ {
+ return x_ != 0 ? base::count (x_) : 0;
+ }
+
+ private:
+ template <typename>
+ friend class shared_ptr;
+
+ X* x_;
+ };
+
+ template <typename X, typename Y>
+ inline bool
+ operator== (const shared_ptr<X>& x, const shared_ptr<Y>& y)
+ {
+ return x.get () == y.get ();
+ }
+
+ template <typename X, typename Y>
+ inline bool
+ operator!= (const shared_ptr<X>& x, const shared_ptr<Y>& y)
+ {
+ return x.get () != y.get ();
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_HXX
diff --git a/libodb/odb/details/shared-ptr/base.cxx b/libodb/odb/details/shared-ptr/base.cxx
new file mode 100644
index 0000000..d937400
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.cxx
@@ -0,0 +1,83 @@
+// file : odb/details/shared-ptr/base.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/shared-ptr/base.hxx>
+#include <odb/details/shared-ptr/exception.hxx>
+
+using std::size_t;
+
+namespace odb
+{
+ namespace details
+ {
+ share shared = share (1);
+ share exclusive = share (2);
+
+ const char* not_shared::
+ what () const ODB_NOTHROW_NOEXCEPT
+ {
+ return "object is not shared";
+ }
+
+ not_shared* not_shared::
+ clone () const
+ {
+ return new not_shared (*this);
+ }
+
+ namespace bits
+ {
+ size_t* locator_common::
+ counter (void* x)
+ {
+ size_t* p (static_cast<size_t*> (x));
+
+ if (*(--p) != 0xDEADBEEF)
+ throw not_shared ();
+
+ return --p;
+ }
+ }
+ }
+}
+
+void*
+#ifdef ODB_CXX11
+operator new (size_t n, odb::details::share s)
+#else
+operator new (size_t n, odb::details::share s) throw (std::bad_alloc)
+#endif
+{
+ if (s == odb::details::shared)
+ {
+ // Here we need to make sure we don't break the alignment of the
+ // returned block. For that we need to know the maximum alignment
+ // of this platform. Twice the pointer size is a good guess for
+ // most platforms.
+ //
+ size_t* p = static_cast<size_t*> (operator new (n + 2 * sizeof (size_t)));
+ *p++ = 1; // Initial count.
+ *p++ = 0xDEADBEEF; // Signature.
+ return p;
+ }
+ else
+ return operator new (n);
+
+}
+
+void
+operator delete (void* p, odb::details::share s) ODB_NOTHROW_NOEXCEPT
+{
+ // This version of operator delete is only called when the c-tor
+ // fails. In this case there is no object and we can just free the
+ // memory.
+ //
+ if (s == odb::details::shared)
+ {
+ size_t* sp = static_cast<size_t*> (p);
+ sp -= 2;
+ operator delete (sp);
+ }
+ else
+ operator delete (p);
+}
diff --git a/libodb/odb/details/shared-ptr/base.hxx b/libodb/odb/details/shared-ptr/base.hxx
new file mode 100644
index 0000000..8cd4c86
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.hxx
@@ -0,0 +1,131 @@
+// file : odb/details/shared-ptr/base.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_BASE_HXX
+#define ODB_DETAILS_SHARED_PTR_BASE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_CXX11, ODB_NOTHROW_NOEXCEPT
+
+#include <new>
+#include <cstddef> // std::size_t
+
+#ifdef ODB_CXX11
+#include <atomic>
+#endif
+
+#include <odb/details/export.hxx>
+#include <odb/details/shared-ptr/counter-type.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct share
+ {
+ explicit
+ share (char id);
+
+ bool
+ operator== (share) const;
+
+ private:
+ char id_;
+ };
+
+ extern LIBODB_EXPORT share shared;
+ extern LIBODB_EXPORT share exclusive;
+ }
+}
+
+#ifdef ODB_CXX11
+LIBODB_EXPORT void*
+operator new (std::size_t, odb::details::share);
+#else
+LIBODB_EXPORT void*
+operator new (std::size_t, odb::details::share) throw (std::bad_alloc);
+#endif
+
+LIBODB_EXPORT void
+operator delete (void*, odb::details::share) ODB_NOTHROW_NOEXCEPT;
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT shared_base
+ {
+ public:
+ shared_base ();
+ shared_base (const shared_base&);
+ shared_base&
+ operator= (const shared_base&);
+
+ void
+ _inc_ref ();
+
+ bool
+ _dec_ref ();
+
+ std::size_t
+ _ref_count () const;
+
+#ifdef ODB_CXX11
+ void*
+ operator new (std::size_t);
+
+ void*
+ operator new (std::size_t, share);
+#else
+ void*
+ operator new (std::size_t) throw (std::bad_alloc);
+
+ void*
+ operator new (std::size_t, share) throw (std::bad_alloc);
+#endif
+
+ void
+ operator delete (void*, share) ODB_NOTHROW_NOEXCEPT;
+
+ void
+ operator delete (void*) ODB_NOTHROW_NOEXCEPT;
+
+ struct refcount_callback
+ {
+ void* arg;
+
+ // Return true if the object should be deleted, false otherwise.
+ //
+ bool (*zero_counter) (void*);
+ };
+
+ protected:
+#ifdef ODB_CXX11
+ std::atomic<std::size_t> counter_;
+#else
+ std::size_t counter_;
+#endif
+ refcount_callback* callback_;
+ };
+
+ template <typename X>
+ inline X*
+ inc_ref (X*);
+
+ template <typename X>
+ inline void
+ dec_ref (X*);
+
+ template <typename X>
+ inline std::size_t
+ ref_count (const X*);
+ }
+}
+
+#include <odb/details/shared-ptr/base.ixx>
+#include <odb/details/shared-ptr/base.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_BASE_HXX
diff --git a/libodb/odb/details/shared-ptr/base.ixx b/libodb/odb/details/shared-ptr/base.ixx
new file mode 100644
index 0000000..1e2fd4b
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.ixx
@@ -0,0 +1,119 @@
+// file : odb/details/shared-ptr/base.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ // share
+ //
+
+ inline share::
+ share (char id)
+ : id_ (id)
+ {
+ }
+
+ inline bool share::
+ operator== (share x) const
+ {
+ return id_ == x.id_;
+ }
+
+ // shared_base
+ //
+
+ inline shared_base::
+ shared_base ()
+ : counter_ (1), callback_ (0)
+ {
+ }
+
+ inline shared_base::
+ shared_base (const shared_base&)
+ : counter_ (1), callback_ (0)
+ {
+ }
+
+ inline shared_base& shared_base::
+ operator= (const shared_base&)
+ {
+ return *this;
+ }
+
+ inline void shared_base::
+ _inc_ref ()
+ {
+#ifdef ODB_CXX11
+ counter_.fetch_add (1, std::memory_order_relaxed);
+#else
+ ++counter_;
+#endif
+ }
+
+ inline bool shared_base::
+ _dec_ref ()
+ {
+ // While there are ways to avoid acquire (which is unnecessary except
+ // when the counter drops to zero), for our use-cases we'd rather keep
+ // it simple.
+ //
+ return
+#ifdef ODB_CXX11
+ counter_.fetch_sub (1, std::memory_order_acq_rel) == 1
+#else
+ --counter_ == 0
+#endif
+ ? callback_ == 0 || callback_->zero_counter (callback_->arg)
+ : false;
+ }
+
+ inline std::size_t shared_base::
+ _ref_count () const
+ {
+#ifdef ODB_CXX11
+ return counter_.load (std::memory_order_relaxed);
+#else
+ return counter_;
+#endif
+ }
+
+#ifdef ODB_CXX11
+ inline void* shared_base::
+ operator new (std::size_t n)
+ {
+ return ::operator new (n);
+ }
+
+ inline void* shared_base::
+ operator new (std::size_t n, share)
+ {
+ return ::operator new (n);
+ }
+#else
+ inline void* shared_base::
+ operator new (std::size_t n) throw (std::bad_alloc)
+ {
+ return ::operator new (n);
+ }
+
+ inline void* shared_base::
+ operator new (std::size_t n, share) throw (std::bad_alloc)
+ {
+ return ::operator new (n);
+ }
+#endif
+
+ inline void shared_base::
+ operator delete (void* p, share) ODB_NOTHROW_NOEXCEPT
+ {
+ ::operator delete (p);
+ }
+
+ inline void shared_base::
+ operator delete (void* p) ODB_NOTHROW_NOEXCEPT
+ {
+ ::operator delete (p);
+ }
+ }
+}
diff --git a/libodb/odb/details/shared-ptr/base.txx b/libodb/odb/details/shared-ptr/base.txx
new file mode 100644
index 0000000..77a957d
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.txx
@@ -0,0 +1,198 @@
+// file : odb/details/shared-ptr/base.txx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/meta/answer.hxx>
+#include <odb/details/meta/polymorphic-p.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace bits
+ {
+ // Support for locating the counter in the memory block.
+ //
+ struct LIBODB_EXPORT locator_common
+ {
+ static std::size_t*
+ counter (void*);
+ };
+
+ template <typename X, bool poly = meta::polymorphic_p<X>::result>
+ struct locator;
+
+ template <typename X>
+ struct locator<X, false>: locator_common
+ {
+ static std::size_t*
+ counter (X* x)
+ {
+ return locator_common::counter (x);
+ }
+ };
+
+ template <typename X>
+ struct locator<X, true>: locator_common
+ {
+ static std::size_t*
+ counter (X* x)
+ {
+ return locator_common::counter (dynamic_cast<void*> (x));
+ }
+ };
+
+ template <typename X>
+ std::size_t*
+ counter (const X* p)
+ {
+ return bits::locator<X>::counter (const_cast<X*> (p));
+ }
+
+ // Counter type and operations.
+ //
+ meta::no test (...);
+ meta::yes test (shared_base*);
+
+ template <typename X,
+ std::size_t A = sizeof (bits::test (reinterpret_cast<X*> (0)))>
+ struct counter_type;
+
+ template <typename X>
+ struct counter_type<X, sizeof (meta::no)>
+ {
+ typedef typename details::counter_type<X>::counter r;
+ };
+
+ template <typename X>
+ struct counter_type<X, sizeof (meta::yes)>
+ {
+ typedef shared_base r;
+ };
+
+ template <typename X, typename Y>
+ struct counter_ops;
+
+ template <typename X>
+ struct counter_ops<X, X>
+ {
+ counter_ops (const X* p) : counter_ (p ? bits::counter (p) : 0) {}
+ counter_ops (const counter_ops& x) : counter_ (x.counter_) {}
+
+ template <typename Z>
+ counter_ops (const counter_ops<Z, Z>& x) : counter_ (x.counter_) {}
+
+ counter_ops&
+ operator= (const counter_ops& x)
+ {
+ counter_ = x.counter_;
+ return *this;
+ }
+
+ template <typename Z>
+ counter_ops&
+ operator= (const counter_ops<Z, Z>& x)
+ {
+ counter_ = x.counter_;
+ return *this;
+ }
+
+ void
+ reset (const X* p)
+ {
+ counter_ = p ? bits::counter (p) : 0;
+ }
+
+ void
+ inc (X*)
+ {
+ (*counter_)++;
+ }
+
+ void
+ dec (X* p)
+ {
+ if (--(*counter_) == 0)
+ {
+ p->~X ();
+
+ // Counter is the top of the memory block.
+ //
+ operator delete (counter_);
+ }
+ }
+
+ std::size_t
+ count (const X*) const
+ {
+ return *counter_;
+ }
+
+ std::size_t* counter_;
+ };
+
+ template <typename Y>
+ struct counter_ops<shared_base, Y>
+ {
+ counter_ops (const Y*) {}
+ counter_ops (const counter_ops&) {}
+
+ template <typename Z>
+ counter_ops (const counter_ops<shared_base, Z>&) {}
+
+ counter_ops&
+ operator= (const counter_ops&)
+ {
+ return *this;
+ }
+
+ template <typename Z>
+ counter_ops&
+ operator= (const counter_ops<shared_base, Z>&)
+ {
+ return *this;
+ }
+
+ void
+ reset (const Y*) {}
+
+ void
+ inc (shared_base* p) {p->_inc_ref ();}
+
+ void
+ dec (Y* p)
+ {
+ if (static_cast<shared_base*> (p)->_dec_ref ())
+ delete p;
+ }
+
+ std::size_t
+ count (const shared_base* p) const {return p->_ref_count ();}
+ };
+ }
+
+ template <typename X>
+ inline X*
+ inc_ref (X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ c.inc (p);
+ return p;
+ }
+
+ template <typename X>
+ inline void
+ dec_ref (X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ c.dec (p);
+ }
+
+ template <typename X>
+ inline std::size_t
+ ref_count (const X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ return c.count (p);
+ }
+ }
+}
diff --git a/libodb/odb/details/shared-ptr/counter-type.hxx b/libodb/odb/details/shared-ptr/counter-type.hxx
new file mode 100644
index 0000000..2b6caad
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/counter-type.hxx
@@ -0,0 +1,23 @@
+// file : odb/details/shared-ptr/counter-type.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
+#define ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename X>
+ struct counter_type
+ {
+ typedef X counter;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
diff --git a/libodb/odb/details/shared-ptr/exception.hxx b/libodb/odb/details/shared-ptr/exception.hxx
new file mode 100644
index 0000000..0ed50be
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/exception.hxx
@@ -0,0 +1,31 @@
+// file : odb/details/shared-ptr/exception.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX
+#define ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/exception.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT not_shared: exception
+ {
+ virtual const char*
+ what () const ODB_NOTHROW_NOEXCEPT;
+
+ virtual not_shared*
+ clone () const;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX
diff --git a/libodb/odb/details/thread.cxx b/libodb/odb/details/thread.cxx
new file mode 100644
index 0000000..b1fbe42
--- /dev/null
+++ b/libodb/odb/details/thread.cxx
@@ -0,0 +1,22 @@
+// file : odb/details/thread.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/thread.hxx>
+
+// We might be compiled with ODB_THREADS_NONE.
+//
+#ifdef ODB_THREADS_CXX11
+
+namespace odb
+{
+ namespace details
+ {
+ void thread::
+ thunk (void* (*f) (void*), void* a, std::promise<void*> p)
+ {
+ p.set_value (f (a));
+ }
+ }
+}
+
+#endif
diff --git a/libodb/odb/details/thread.hxx b/libodb/odb/details/thread.hxx
new file mode 100644
index 0000000..9095f68
--- /dev/null
+++ b/libodb/odb/details/thread.hxx
@@ -0,0 +1,65 @@
+// file : odb/details/thread.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_THREAD_HXX
+#define ODB_DETAILS_THREAD_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx>
+#include <odb/details/export.hxx>
+
+#ifdef ODB_THREADS_NONE
+# error no thread support available
+#elif defined(ODB_THREADS_CXX11)
+# include <thread>
+# include <future>
+# include <utility> // move()
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT thread
+ {
+ public:
+ thread (void* (*thread_func) (void*), void* arg = 0)
+ {
+ std::promise<void*> p;
+ f_ = p.get_future ();
+ t_ = std::thread (thunk, thread_func, arg, std::move (p));
+ }
+
+ void*
+ join ()
+ {
+ f_.wait ();
+ t_.join ();
+ return f_.get ();
+ }
+
+ thread (const thread&) = delete;
+ thread& operator= (const thread&) = delete;
+
+ private:
+ static void
+ thunk (void* (*) (void*), void*, std::promise<void*>);
+
+ private:
+ std::thread t_;
+ std::future<void*> f_;
+ };
+ }
+}
+
+#elif defined(ODB_THREADS_POSIX)
+#include <odb/details/posix/thread.hxx>
+#elif defined(ODB_THREADS_WIN32)
+#include <odb/details/win32/thread.hxx>
+#else
+# error unknown threading model
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_THREAD_HXX
diff --git a/libodb/odb/details/tls.hxx b/libodb/odb/details/tls.hxx
new file mode 100644
index 0000000..de6c344
--- /dev/null
+++ b/libodb/odb/details/tls.hxx
@@ -0,0 +1,168 @@
+// file : odb/details/tls.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_TLS_HXX
+#define ODB_DETAILS_TLS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx>
+
+#ifdef ODB_THREADS_NONE
+
+# define ODB_TLS_POINTER(type) type*
+# define ODB_TLS_OBJECT(type) type
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline T&
+ tls_get (T& x)
+ {
+ return x;
+ }
+
+ // If early destructions is possible, destroy the object and free
+ // any allocated resources.
+ //
+ template <typename T>
+ inline void
+ tls_free (T&)
+ {
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (T* p)
+ {
+ return p;
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (T*& rp, T1* p)
+ {
+ rp = p;
+ }
+ }
+}
+
+#elif defined(ODB_THREADS_CXX11)
+
+// Apparently Apple's Clang "temporarily disabled" C++11 thread_local until
+// they can implement a "fast" version, which reportedly happened in XCode 8.
+// So for now we will continue using __thread for this target.
+//
+# if defined(__apple_build_version__) && __apple_build_version__ < 8000000
+# define ODB_TLS_POINTER(type) __thread type*
+# define ODB_TLS_OBJECT(type) thread_local type
+# else
+# define ODB_TLS_POINTER(type) thread_local type*
+# define ODB_TLS_OBJECT(type) thread_local type
+# endif
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline T&
+ tls_get (T& x)
+ {
+ return x;
+ }
+
+ template <typename T>
+ inline void
+ tls_free (T&)
+ {
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (T* p)
+ {
+ return p;
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (T*& rp, T1* p)
+ {
+ rp = p;
+ }
+ }
+}
+
+#elif defined(ODB_THREADS_POSIX)
+
+# include <odb/details/posix/tls.hxx>
+
+# ifdef ODB_THREADS_TLS_KEYWORD
+# define ODB_TLS_POINTER(type) __thread type*
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline T*
+ tls_get (T* p)
+ {
+ return p;
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (T*& rp, T1* p)
+ {
+ rp = p;
+ }
+ }
+}
+
+# else
+# define ODB_TLS_POINTER(type) tls<type*>
+# endif
+# define ODB_TLS_OBJECT(type) tls<type>
+
+#elif defined(ODB_THREADS_WIN32)
+
+# include <odb/details/win32/tls.hxx>
+
+# ifdef ODB_THREADS_TLS_DECLSPEC
+# define ODB_TLS_POINTER(type) __declspec(thread) type*
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline T*
+ tls_get (T* p)
+ {
+ return p;
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (T*& rp, T1* p)
+ {
+ rp = p;
+ }
+ }
+}
+
+# else
+# define ODB_TLS_POINTER(type) tls<type*>
+# endif
+# define ODB_TLS_OBJECT(type) tls<type>
+#else
+# error unknown threading model
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_TLS_HXX
diff --git a/libodb/odb/details/transfer-ptr.hxx b/libodb/odb/details/transfer-ptr.hxx
new file mode 100644
index 0000000..4b63df6
--- /dev/null
+++ b/libodb/odb/details/transfer-ptr.hxx
@@ -0,0 +1,73 @@
+// file : odb/details/transfer-ptr.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_TRANSFER_PTR_HXX
+#define ODB_DETAILS_TRANSFER_PTR_HXX
+
+#include <odb/pre.hxx>
+
+#include <memory> // std::auto_ptr, std::unique_ptr
+
+#include <odb/details/config.hxx> // ODB_CXX11
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ class transfer_ptr
+ {
+ public:
+ typedef T element_type;
+
+ transfer_ptr (): p_ (0) {}
+
+#ifndef ODB_CXX11
+ template <typename T1>
+ transfer_ptr (std::auto_ptr<T1> p): p_ (p.release ()) {}
+
+ private:
+ transfer_ptr& operator= (const transfer_ptr&);
+
+ public:
+ // In our usage transfer_ptr is always created implicitly and
+ // never const. So while this is not very clean, it is legal.
+ // Plus it will all go away once we drop C++98 (I can hardly
+ // wait).
+ //
+ transfer_ptr (const transfer_ptr& p)
+ : p_ (const_cast<transfer_ptr&> (p).transfer ()) {}
+#else
+#ifdef ODB_CXX11_NULLPTR
+ transfer_ptr (std::nullptr_t): p_ (0) {}
+#endif
+ template <typename T1>
+ transfer_ptr (std::unique_ptr<T1>&& p): p_ (p.release ()) {}
+
+ private:
+ transfer_ptr (const transfer_ptr&);
+ transfer_ptr& operator= (const transfer_ptr&);
+
+ public:
+ transfer_ptr (transfer_ptr&& p) noexcept: p_ (p.transfer ()) {}
+#endif
+
+ ~transfer_ptr () {delete p_;}
+
+ T*
+ transfer ()
+ {
+ T* r (p_);
+ p_ = 0;
+ return r;
+ }
+
+ private:
+ T* p_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_TRANSFER_PTR_HXX
diff --git a/libodb/odb/details/type-info.hxx b/libodb/odb/details/type-info.hxx
new file mode 100644
index 0000000..fe01699
--- /dev/null
+++ b/libodb/odb/details/type-info.hxx
@@ -0,0 +1,36 @@
+// file : odb/details/type-info.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_TYPE_INFO_HXX
+#define ODB_DETAILS_TYPE_INFO_HXX
+
+#include <odb/pre.hxx>
+
+#include <typeinfo>
+
+namespace odb
+{
+ namespace details
+ {
+ struct type_info_comparator
+ {
+ bool
+ operator() (const std::type_info* x, const std::type_info* y) const
+ {
+ // XL C++ on AIX has buggy type_info::before() in that
+ // it returns true for two different type_info objects
+ // that happened to be for the same type.
+ //
+#if defined(__xlC__) && defined(_AIX)
+ return *x != *y && x->before (*y);
+#else
+ return x->before (*y);
+#endif
+ }
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_TYPE_INFO_HXX
diff --git a/libodb/odb/details/unique-ptr.hxx b/libodb/odb/details/unique-ptr.hxx
new file mode 100644
index 0000000..06b2c76
--- /dev/null
+++ b/libodb/odb/details/unique-ptr.hxx
@@ -0,0 +1,95 @@
+// file : odb/details/unique-ptr.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_UNIQUE_PTR_HXX
+#define ODB_DETAILS_UNIQUE_PTR_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ class unique_ptr
+ {
+ public:
+ typedef T element_type;
+
+ explicit unique_ptr (T* p = 0): p_ (p) {}
+ ~unique_ptr () {delete p_;}
+
+#ifdef ODB_CXX11
+ unique_ptr (unique_ptr&& p) noexcept: p_ (p.p_) {p.p_ = 0;}
+ unique_ptr& operator= (unique_ptr&& p) noexcept
+ {
+ if (this != &p)
+ {
+ delete p_;
+ p_ = p.p_;
+ p.p_ = 0;
+ }
+ return *this;
+ }
+#endif
+
+ private:
+ unique_ptr (const unique_ptr&);
+ unique_ptr& operator= (const unique_ptr&);
+
+ public:
+ T*
+ operator-> () const {return p_;}
+
+ T&
+ operator* () const {return *p_;}
+
+ typedef T* unique_ptr::*unspecified_bool_type;
+ operator unspecified_bool_type () const
+ {
+ return p_ != 0 ? &unique_ptr::p_ : 0;
+ }
+
+ T*
+ get () const {return p_;}
+
+ void
+ reset (T* p = 0)
+ {
+ delete p_;
+ p_ = p;
+ }
+
+ T*
+ release ()
+ {
+ T* r (p_);
+ p_ = 0;
+ return r;
+ }
+
+ private:
+ T* p_;
+ };
+
+ template <typename T1, typename T2>
+ inline bool
+ operator== (const unique_ptr<T1>& a, const unique_ptr<T2>& b)
+ {
+ return a.get () == b.get ();
+ }
+
+ template <typename T1, typename T2>
+ inline bool
+ operator!= (const unique_ptr<T1>& a, const unique_ptr<T2>& b)
+ {
+ return a.get () != b.get ();
+ }
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_UNIQUE_PTR_HXX
diff --git a/libodb/odb/details/unused.hxx b/libodb/odb/details/unused.hxx
new file mode 100644
index 0000000..8364c44
--- /dev/null
+++ b/libodb/odb/details/unused.hxx
@@ -0,0 +1,21 @@
+// file : odb/details/unused.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_UNUSED_DETAILS_HXX
+#define ODB_UNUSED_DETAILS_HXX
+
+#include <odb/pre.hxx>
+
+// VC++ and xlC don't like the (void)x expression if x is a reference
+// to an incomplete type. On the other hand, GCC warns that (void*)&x
+// doesn't have any effect.
+//
+#if defined(_MSC_VER) || defined(__xlC__)
+# define ODB_POTENTIALLY_UNUSED(x) (void*)&x
+#else
+# define ODB_POTENTIALLY_UNUSED(x) (void)x
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_UNUSED_DETAILS_HXX
diff --git a/libodb/odb/details/win32/condition.cxx b/libodb/odb/details/win32/condition.cxx
new file mode 100644
index 0000000..3a4b605
--- /dev/null
+++ b/libodb/odb/details/win32/condition.cxx
@@ -0,0 +1,54 @@
+// file : odb/details/win32/condition.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/win32/condition.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void condition::
+ signal ()
+ {
+ mutex_.lock ();
+
+ if (waiters_ > signals_)
+ {
+ if (signals_++ == 0)
+ {
+ if (SetEvent (event_) == 0)
+ throw win32_exception ();
+ }
+ }
+
+ mutex_.unlock ();
+ }
+
+ void condition::
+ wait (lock&)
+ {
+ // When we enter this functions the mutex is locked. When we
+ // return from this function the mutex must be locked.
+ //
+ waiters_++;
+ mutex_.unlock ();
+
+ if (WaitForSingleObject (event_, INFINITE) != 0)
+ throw win32_exception ();
+
+ mutex_.lock ();
+ waiters_--;
+ signals_--;
+
+ if (signals_ > 0)
+ {
+ // Wake up the next thread.
+ //
+ if (SetEvent (event_) == 0)
+ throw win32_exception ();
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/condition.hxx b/libodb/odb/details/win32/condition.hxx
new file mode 100644
index 0000000..69972a0
--- /dev/null
+++ b/libodb/odb/details/win32/condition.hxx
@@ -0,0 +1,52 @@
+// file : odb/details/win32/condition.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_CONDITION_HXX
+#define ODB_DETAILS_WIN32_CONDITION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/export.hxx>
+#include <odb/details/win32/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class lock;
+
+ class LIBODB_EXPORT condition
+ {
+ public:
+ ~condition ();
+ condition (mutex&);
+
+ void
+ signal ();
+
+ void
+ wait (lock&);
+
+ private:
+ condition (const condition&);
+ condition& operator= (const condition&);
+
+ private:
+ mutex& mutex_;
+ HANDLE event_;
+
+ std::size_t waiters_;
+ std::size_t signals_;
+ };
+ }
+}
+
+#include <odb/details/win32/condition.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_CONDITION_HXX
diff --git a/libodb/odb/details/win32/condition.ixx b/libodb/odb/details/win32/condition.ixx
new file mode 100644
index 0000000..37a2bac
--- /dev/null
+++ b/libodb/odb/details/win32/condition.ixx
@@ -0,0 +1,30 @@
+// file : odb/details/win32/condition.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline condition::
+ ~condition ()
+ {
+ CloseHandle (event_);
+ }
+
+ inline condition::
+ condition (mutex& mutex)
+ : mutex_ (mutex), waiters_ (0), signals_ (0)
+ {
+ // Auto-reset event. Releases one waiting thread and automatically
+ // resets the event state. If no threads are waiting the event
+ // remains signalled.
+ //
+ event_ = CreateEvent (0, false, false, 0);
+
+ if (event_ == 0)
+ throw win32_exception ();
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/dll.cxx b/libodb/odb/details/win32/dll.cxx
new file mode 100644
index 0000000..3f674ba
--- /dev/null
+++ b/libodb/odb/details/win32/dll.cxx
@@ -0,0 +1,48 @@
+// file : odb/details/win32/dll.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// If we are building a static library then omit DllMain.
+
+#ifdef LIBODB_SHARED_BUILD
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/win32/init.hxx>
+
+using namespace odb::details;
+
+extern "C" BOOL WINAPI
+DllMain (HINSTANCE, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ process_start ();
+ thread_start ();
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ thread_start ();
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ thread_end ();
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ thread_end ();
+ process_end (reserved == NULL);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+#endif
diff --git a/libodb/odb/details/win32/exceptions.cxx b/libodb/odb/details/win32/exceptions.cxx
new file mode 100644
index 0000000..3cf11c2
--- /dev/null
+++ b/libodb/odb/details/win32/exceptions.cxx
@@ -0,0 +1,22 @@
+// file : odb/details/win32/exceptions.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ const char* win32_exception::
+ what () const ODB_NOTHROW_NOEXCEPT
+ {
+ return "Win32 API error";
+ }
+
+ win32_exception* win32_exception::
+ clone () const
+ {
+ return new win32_exception (*this);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/exceptions.hxx b/libodb/odb/details/win32/exceptions.hxx
new file mode 100644
index 0000000..b61a447
--- /dev/null
+++ b/libodb/odb/details/win32/exceptions.hxx
@@ -0,0 +1,40 @@
+// file : odb/details/win32/exceptions.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_EXCEPTIONS_HXX
+#define ODB_DETAILS_WIN32_EXCEPTIONS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/export.hxx>
+#include <odb/details/exception.hxx>
+#include <odb/details/win32/windows.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT win32_exception: details::exception
+ {
+ win32_exception () : code_ (GetLastError ()) {}
+ win32_exception (DWORD code) : code_ (code) {}
+
+ DWORD
+ code () const {return code_;}
+
+ virtual const char*
+ what () const ODB_NOTHROW_NOEXCEPT;
+
+ virtual win32_exception*
+ clone () const;
+
+ private:
+ DWORD code_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_EXCEPTIONS_HXX
diff --git a/libodb/odb/details/win32/init.cxx b/libodb/odb/details/win32/init.cxx
new file mode 100644
index 0000000..f6e0f9a
--- /dev/null
+++ b/libodb/odb/details/win32/init.cxx
@@ -0,0 +1,41 @@
+// file : odb/details/win32/init.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/init.hxx>
+#include <odb/details/win32/once-init.hxx>
+#include <odb/details/win32/tls-init.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ process_start ()
+ {
+ // The order is important.
+ //
+ once_process_start ();
+ tls_process_start ();
+ }
+
+ void
+ process_end (bool safe)
+ {
+ // The order is important.
+ //
+ tls_process_end (safe);
+ once_process_end (safe);
+ }
+
+ void
+ thread_start ()
+ {
+ }
+
+ void
+ thread_end ()
+ {
+ tls_thread_end ();
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/init.hxx b/libodb/odb/details/win32/init.hxx
new file mode 100644
index 0000000..1c15ffd
--- /dev/null
+++ b/libodb/odb/details/win32/init.hxx
@@ -0,0 +1,36 @@
+// file : odb/details/win32/init.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_INIT_HXX
+#define ODB_DETAILS_WIN32_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ process_start ();
+
+ // The safe parameter indicates whether it is safe to free heap objects.
+ // If the process is terminated by a call to ExitProcess(), some threads
+ // might have been killed leaving things in inconsistent state.
+ //
+ void
+ process_end (bool safe = true);
+
+ void
+ thread_start ();
+
+ // This function may be called even for thread for which thread_start()
+ // hasn't been called.
+ //
+ void
+ thread_end ();
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_INIT_HXX
diff --git a/libodb/odb/details/win32/lock.hxx b/libodb/odb/details/win32/lock.hxx
new file mode 100644
index 0000000..2e81ac6
--- /dev/null
+++ b/libodb/odb/details/win32/lock.hxx
@@ -0,0 +1,49 @@
+// file : odb/details/win32/lock.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_LOCK_HXX
+#define ODB_DETAILS_WIN32_LOCK_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // Critical section lock. Not exported; for internal use only.
+ //
+ struct win32_lock
+ {
+ win32_lock (CRITICAL_SECTION& cs)
+ : cs_ (&cs)
+ {
+ EnterCriticalSection (cs_);
+ }
+
+ ~win32_lock ()
+ {
+ if (cs_ != 0)
+ LeaveCriticalSection (cs_);
+ }
+
+ void
+ unlock ()
+ {
+ if (cs_ != 0)
+ {
+ LeaveCriticalSection (cs_);
+ cs_ = 0;
+ }
+ }
+
+ private:
+ CRITICAL_SECTION* cs_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_LOCK_HXX
diff --git a/libodb/odb/details/win32/mutex.hxx b/libodb/odb/details/win32/mutex.hxx
new file mode 100644
index 0000000..b2cd997
--- /dev/null
+++ b/libodb/odb/details/win32/mutex.hxx
@@ -0,0 +1,43 @@
+// file : odb/details/win32/mutex.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_MUTEX_HXX
+#define ODB_DETAILS_WIN32_MUTEX_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT mutex
+ {
+ public:
+ ~mutex ();
+ mutex ();
+
+ void
+ lock ();
+
+ void
+ unlock ();
+
+ private:
+ mutex (const mutex&);
+ mutex& operator= (const mutex&);
+
+ private:
+ friend class condition;
+ CRITICAL_SECTION cs_;
+ };
+ }
+}
+
+#include <odb/details/win32/mutex.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_MUTEX_HXX
diff --git a/libodb/odb/details/win32/mutex.ixx b/libodb/odb/details/win32/mutex.ixx
new file mode 100644
index 0000000..bb06415
--- /dev/null
+++ b/libodb/odb/details/win32/mutex.ixx
@@ -0,0 +1,32 @@
+// file : odb/details/win32/mutex.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ inline mutex::
+ ~mutex ()
+ {
+ DeleteCriticalSection (&cs_);
+ }
+
+ inline mutex::
+ mutex ()
+ {
+ InitializeCriticalSection (&cs_);
+ }
+
+ inline void mutex::
+ lock ()
+ {
+ EnterCriticalSection (&cs_);
+ }
+
+ inline void mutex::
+ unlock ()
+ {
+ LeaveCriticalSection (&cs_);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/once-init.hxx b/libodb/odb/details/win32/once-init.hxx
new file mode 100644
index 0000000..a465c90
--- /dev/null
+++ b/libodb/odb/details/win32/once-init.hxx
@@ -0,0 +1,23 @@
+// file : odb/details/win32/once-init.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_ONCE_INIT_HXX
+#define ODB_DETAILS_WIN32_ONCE_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ once_process_start ();
+
+ void
+ once_process_end (bool safe);
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_ONCE_INIT_HXX
diff --git a/libodb/odb/details/win32/once.cxx b/libodb/odb/details/win32/once.cxx
new file mode 100644
index 0000000..7b98d80
--- /dev/null
+++ b/libodb/odb/details/win32/once.cxx
@@ -0,0 +1,26 @@
+// file : odb/details/win32/once.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/win32/once.hxx>
+#include <odb/details/win32/once-init.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ CRITICAL_SECTION win32_once_cs_;
+
+ void
+ once_process_start ()
+ {
+ InitializeCriticalSection (&win32_once_cs_);
+ }
+
+ void
+ once_process_end (bool)
+ {
+ DeleteCriticalSection (&win32_once_cs_);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/once.hxx b/libodb/odb/details/win32/once.hxx
new file mode 100644
index 0000000..45748b8
--- /dev/null
+++ b/libodb/odb/details/win32/once.hxx
@@ -0,0 +1,50 @@
+// file : odb/details/win32/once.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_ONCE_HXX
+#define ODB_DETAILS_WIN32_ONCE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT once
+ {
+ public:
+ once ();
+
+ void
+ call (void (*func) ());
+
+ private:
+ once (const once&);
+ once& operator= (const once&);
+
+ private:
+ bool called_;
+ };
+
+ // Low-level, POSIX-like API that can be used safely during static
+ // initialization (that is, win32_once() can be called during static
+ // initialization) provided once_process_start() has been called.
+ //
+ typedef unsigned int win32_once_t;
+ const win32_once_t WIN32_ONCE_INIT = 0;
+
+ LIBODB_EXPORT void
+ win32_once (win32_once_t&, void (*func) ());
+
+ extern LIBODB_EXPORT CRITICAL_SECTION win32_once_cs_;
+ }
+}
+
+#include <odb/details/win32/once.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_ONCE_HXX
diff --git a/libodb/odb/details/win32/once.ixx b/libodb/odb/details/win32/once.ixx
new file mode 100644
index 0000000..1638706
--- /dev/null
+++ b/libodb/odb/details/win32/once.ixx
@@ -0,0 +1,42 @@
+// file : odb/details/win32/once.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/lock.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline void
+ win32_once (win32_once_t& o, void (*func) ())
+ {
+ win32_lock l (win32_once_cs_);
+
+ if (o == 0)
+ {
+ o = 1;
+ l.unlock ();
+ func ();
+ }
+ }
+
+ inline once::
+ once ()
+ : called_ (false)
+ {
+ }
+
+ inline void once::
+ call (void (*func) ())
+ {
+ win32_lock l (win32_once_cs_);
+
+ if (!called_)
+ {
+ called_ = true;
+ l.unlock ();
+ func ();
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/thread.cxx b/libodb/odb/details/win32/thread.cxx
new file mode 100644
index 0000000..46720d4
--- /dev/null
+++ b/libodb/odb/details/win32/thread.cxx
@@ -0,0 +1,88 @@
+// file : odb/details/win32/thread.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <process.h> // _beginthreadex, _endthreadex
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/win32/thread.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+unsigned int __stdcall
+odb_thread_thunk (void* arg)
+{
+ odb::details::thread::thread_thunk (arg);
+ _endthreadex (0);
+ return 0;
+}
+
+namespace odb
+{
+ namespace details
+ {
+ void thread::
+ thread_thunk (void* arg)
+ {
+ data* d (static_cast<data*> (arg));
+ d->ret = d->func (d->arg);
+ d->mutex.lock ();
+ unsigned char count = --d->count;
+ d->mutex.unlock ();
+
+ if (count == 0)
+ delete d;
+ }
+
+ thread::
+ ~thread ()
+ {
+ if (handle_ != 0)
+ {
+ CloseHandle (handle_);
+
+ // Win32 mutex implementation does not throw.
+ //
+ data_->mutex.lock ();
+ unsigned char count = --data_->count;
+ data_->mutex.unlock ();
+
+ if (count == 0)
+ delete data_;
+ }
+ }
+
+ thread::
+ thread (void* (*func) (void*), void* arg)
+ {
+ unique_ptr<data> d (new data);
+ d->func = func;
+ d->arg = arg;
+ d->count = 2; // One for the thread and one for us.
+
+ handle_ = (HANDLE)_beginthreadex (
+ 0, 0, &odb_thread_thunk, d.get (), 0, 0);
+
+ if (handle_ == 0)
+ throw win32_exception ();
+
+ data_ = d.release ();
+ }
+
+ void* thread::
+ join ()
+ {
+ void* r;
+
+ if (WaitForSingleObject (handle_, INFINITE) != 0)
+ throw win32_exception ();
+
+ r = data_->ret;
+
+ CloseHandle (handle_);
+ delete data_;
+ handle_ = 0;
+ data_ = 0;
+ return r;
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/thread.hxx b/libodb/odb/details/win32/thread.hxx
new file mode 100644
index 0000000..a4e1a15
--- /dev/null
+++ b/libodb/odb/details/win32/thread.hxx
@@ -0,0 +1,59 @@
+// file : odb/details/win32/thread.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_THREAD_HXX
+#define ODB_DETAILS_WIN32_THREAD_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/export.hxx>
+#include <odb/details/win32/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT thread
+ {
+ public:
+ ~thread ();
+ thread (void* (*thread_func) (void*), void* arg = 0);
+
+ void*
+ join ();
+
+ private:
+ thread (const thread&);
+ thread& operator= (const thread&);
+
+ private:
+ typedef void* (*thread_func) (void*);
+
+ struct data
+ {
+ thread_func func;
+ void* arg;
+ void* ret;
+
+ // Thread-safe reference counter.
+ //
+ details::mutex mutex;
+ unsigned char count;
+ };
+
+
+ public:
+ static void
+ thread_thunk (void*);
+
+ private:
+ HANDLE handle_;
+ data* data_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_THREAD_HXX
diff --git a/libodb/odb/details/win32/tls-init.hxx b/libodb/odb/details/win32/tls-init.hxx
new file mode 100644
index 0000000..0a44a10
--- /dev/null
+++ b/libodb/odb/details/win32/tls-init.hxx
@@ -0,0 +1,26 @@
+// file : odb/details/win32/tls-init.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_TLS_INIT_HXX
+#define ODB_DETAILS_WIN32_TLS_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ tls_process_start ();
+
+ void
+ tls_process_end (bool safe);
+
+ void
+ tls_thread_end ();
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_TLS_INIT_HXX
diff --git a/libodb/odb/details/win32/tls.cxx b/libodb/odb/details/win32/tls.cxx
new file mode 100644
index 0000000..2edc364
--- /dev/null
+++ b/libodb/odb/details/win32/tls.cxx
@@ -0,0 +1,245 @@
+// file : odb/details/win32/tls.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <winerror.h> // ERROR_INVALID_INDEX
+
+#include <new>
+#include <cstddef> // std::size_t
+
+#include <odb/details/win32/lock.hxx>
+#include <odb/details/win32/tls.hxx>
+#include <odb/details/win32/tls-init.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+#ifdef _MSC_VER
+# pragma warning (disable:4200) // zero-sized array in struct
+#endif
+
+using namespace std;
+
+namespace odb
+{
+ namespace details
+ {
+ typedef void (*dtor_func) (void*);
+
+ struct entry
+ {
+ void* value;
+ dtor_func dtor;
+ };
+
+ struct thread_data
+ {
+ size_t size;
+ size_t capacity;
+ entry entries[0];
+ };
+
+ struct process_data
+ {
+ size_t size;
+ size_t capacity;
+ dtor_func dtors[0];
+ };
+
+ static DWORD index_ = TLS_OUT_OF_INDEXES;
+ static CRITICAL_SECTION cs_;
+ static process_data* proc_data_;
+
+ const size_t init_capacity = 4;
+
+ void
+ tls_process_start ()
+ {
+ index_ = TlsAlloc ();
+
+ if (index_ == TLS_OUT_OF_INDEXES)
+ throw win32_exception ();
+
+ InitializeCriticalSection (&cs_);
+
+ process_data* pd (
+ static_cast<process_data*> (
+ operator new (
+ sizeof (process_data) + sizeof (dtor_func) * init_capacity)));
+
+ pd->size = 0;
+ pd->capacity = init_capacity;
+ memset (pd->dtors, 0, sizeof (dtor_func) * init_capacity);
+
+ proc_data_ = pd;
+ }
+
+ void
+ tls_process_end (bool)
+ {
+ operator delete (proc_data_);
+ DeleteCriticalSection (&cs_);
+
+ if (index_ != TLS_OUT_OF_INDEXES)
+ {
+ if (!TlsFree (index_))
+ throw win32_exception ();
+ }
+ }
+
+ void
+ tls_thread_end ()
+ {
+ if (thread_data* d = static_cast<thread_data*> (TlsGetValue (index_)))
+ {
+ // Call destructors. Implement the pthread semantics in that the
+ // destructors are called until all the values become 0.
+ //
+ for (bool pass (true); pass;)
+ {
+ pass = false;
+
+ for (size_t i (0); i < d->size; ++i)
+ {
+ if (d->entries[i].dtor != 0 && d->entries[i].value != 0)
+ {
+ pass = true;
+ void* tmp (d->entries[i].value);
+ d->entries[i].value = 0;
+ d->entries[i].dtor (tmp);
+ }
+ }
+ }
+
+ operator delete (d);
+ }
+ }
+
+ //
+ // tls_common
+ //
+
+ std::size_t tls_common::
+ _allocate (dtor_func dtor)
+ {
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+ size_t c (proc_data_->capacity);
+
+ if (n == c)
+ {
+ c *= 2;
+
+ // Try to do "atomic" switch-over so that proc_data_ always points
+ // to memory that can be freed even if this thread is killed in the
+ // middle.
+ //
+ process_data* pd (
+ static_cast<process_data*> (
+ operator new (sizeof (process_data) + sizeof (dtor_func) * c)));
+
+ memcpy (pd->dtors, proc_data_->dtors, n * sizeof (dtor_func));
+ memset (pd->dtors + n, 0, sizeof (dtor_func) * (c - n));
+
+ pd->size = n;
+ pd->capacity = c;
+
+ process_data* old (proc_data_);
+ proc_data_ = pd;
+ operator delete (old);
+ }
+
+ proc_data_->dtors[n] = dtor;
+ return proc_data_->size++;
+ }
+
+ void* tls_common::
+ _get (std::size_t key)
+ {
+ if (thread_data* d = static_cast<thread_data*> (TlsGetValue (index_)))
+ {
+ if (key < d->size)
+ return d->entries[key].value;
+ }
+
+ // Check if this key is valid.
+ //
+ win32_lock l (cs_);
+
+ if (key < proc_data_->size)
+ return 0;
+
+ throw win32_exception (ERROR_INVALID_INDEX);
+ }
+
+ void tls_common::
+ _set (std::size_t key, void* value)
+ {
+ thread_data* d (static_cast<thread_data*> (TlsGetValue (index_)));
+
+ if (d != 0 && key < d->capacity)
+ {
+ if (key >= d->size)
+ {
+ // Check if this key is valid. If so then we need to copy
+ // dtors for new slots.
+ //
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+
+ if (key >= n)
+ throw win32_exception (ERROR_INVALID_INDEX);
+
+ for (size_t i (d->size); i < n; ++i)
+ d->entries[i].dtor = proc_data_->dtors[i];
+
+ d->size = n;
+ }
+
+ d->entries[key].value = value;
+ }
+ else
+ {
+ // Check if this key is valid. If so then we need to (re)-allocate
+ // our storage.
+ //
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+
+ if (key >= n)
+ throw win32_exception (ERROR_INVALID_INDEX);
+
+ size_t c (proc_data_->capacity);
+
+ thread_data* nd (
+ static_cast<thread_data*> (
+ operator new (sizeof (thread_data) + sizeof (entry) * c)));
+
+ size_t on (d == 0 ? 0 : d->size);
+
+ // Copy over the data.
+ //
+ if (on != 0)
+ memcpy (nd->entries, d->entries, sizeof (entry) * on);
+
+ // Zero out the rest.
+ //
+ memset (nd->entries + on, 0, sizeof (entry) * (c - on));
+
+ // Assign destructors to new slots [on, n).
+ //
+ for (size_t i (on); i < n; ++i)
+ nd->entries[i].dtor = proc_data_->dtors[i];
+
+ nd->size = n;
+ nd->capacity = c;
+
+ operator delete (d);
+ TlsSetValue (index_, nd);
+
+ nd->entries[key].value = value;
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/tls.hxx b/libodb/odb/details/win32/tls.hxx
new file mode 100644
index 0000000..2a75cc8
--- /dev/null
+++ b/libodb/odb/details/win32/tls.hxx
@@ -0,0 +1,120 @@
+// file : odb/details/win32/tls.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_TLS_HXX
+#define ODB_DETAILS_WIN32_TLS_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/export.hxx>
+#include <odb/details/win32/once.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT tls_common
+ {
+ public:
+ static std::size_t
+ _allocate (void (*dtor) (void*));
+
+ static void*
+ _get (std::size_t key);
+
+ static void
+ _set (std::size_t key, void* value);
+ };
+
+ template <typename T>
+ class tls: protected tls_common
+ {
+ public:
+ tls ();
+
+ T&
+ get () const;
+
+ void
+ free ();
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ static void
+ destructor (void*);
+
+ private:
+ static win32_once_t once_;
+ static std::size_t key_;
+ };
+
+ template <typename T>
+ class tls<T*>: protected tls_common
+ {
+ public:
+ tls ();
+
+ T*
+ get () const;
+
+ void
+ set (T* p);
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ private:
+ static win32_once_t once_;
+ static std::size_t key_;
+ };
+
+ template <typename T>
+ inline T&
+ tls_get (const tls<T>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T>
+ inline void
+ tls_free (tls<T>& t)
+ {
+ t.free ();
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (const tls<T*>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (tls<T*>& t, T1* p1)
+ {
+ T* p (p1);
+ t.set (p);
+ }
+ }
+}
+
+#include <odb/details/win32/tls.ixx>
+#include <odb/details/win32/tls.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_TLS_HXX
diff --git a/libodb/odb/details/win32/tls.ixx b/libodb/odb/details/win32/tls.ixx
new file mode 100644
index 0000000..fbcc3dd
--- /dev/null
+++ b/libodb/odb/details/win32/tls.ixx
@@ -0,0 +1,20 @@
+// file : odb/details/win32/tls.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline tls<T>::
+ tls ()
+ {
+ }
+
+ template <typename T>
+ inline tls<T*>::
+ tls ()
+ {
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/tls.txx b/libodb/odb/details/win32/tls.txx
new file mode 100644
index 0000000..96bed4c
--- /dev/null
+++ b/libodb/odb/details/win32/tls.txx
@@ -0,0 +1,94 @@
+// file : odb/details/win32/tls.txx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // tls<T>
+ //
+ template <typename T>
+ win32_once_t tls<T>::once_= WIN32_ONCE_INIT;
+
+ template <typename T>
+ size_t tls<T>::key_;
+
+ template <typename T>
+ T& tls<T>::
+ get () const
+ {
+ win32_once (once_, key_init);
+
+ if (void* v = _get (key_))
+ return *static_cast<T*> (v);
+
+ unique_ptr<T> p (new T);
+ _set (key_, p.get ());
+
+ T& r (*p);
+ p.release ();
+ return r;
+ }
+
+ template <typename T>
+ void tls<T>::
+ free ()
+ {
+ win32_once (once_, key_init);
+
+ if (void* v = _get (key_))
+ {
+ _set (key_, 0);
+ delete static_cast<T*> (v);
+ }
+ }
+
+ template <typename T>
+ void tls<T>::
+ key_init ()
+ {
+ key_ = _allocate (destructor);
+ }
+
+ template <typename T>
+ void tls<T>::
+ destructor (void* v)
+ {
+ delete static_cast<T*> (v);
+ }
+
+ // tls<T*>
+ //
+ template <typename T>
+ win32_once_t tls<T*>::once_ = WIN32_ONCE_INIT;
+
+ template <typename T>
+ size_t tls<T*>::key_;
+
+ template <typename T>
+ T* tls<T*>::
+ get () const
+ {
+ win32_once (once_, key_init);
+ return static_cast<T*> (_get (key_));
+ }
+
+ template <typename T>
+ void tls<T*>::
+ set (T* p)
+ {
+ win32_once (once_, key_init);
+ _set (key_, p);
+ }
+
+ template <typename T>
+ void tls<T*>::
+ key_init ()
+ {
+ key_ = _allocate (0);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/windows.hxx b/libodb/odb/details/win32/windows.hxx
new file mode 100644
index 0000000..9ff4cb4
--- /dev/null
+++ b/libodb/odb/details/win32/windows.hxx
@@ -0,0 +1,33 @@
+// file : odb/details/win32/windows.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_WINDOWS_HXX
+#define ODB_DETAILS_WIN32_WINDOWS_HXX
+
+#include <odb/pre.hxx>
+
+// Try to include <windows.h> so that it doesn't mess other things up.
+//
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# ifndef NOMINMAX // No min and max macros.
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+# undef WIN32_LEAN_AND_MEAN
+#else
+# ifndef NOMINMAX
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_WINDOWS_HXX
diff --git a/libodb/odb/details/wrapper-p.hxx b/libodb/odb/details/wrapper-p.hxx
new file mode 100644
index 0000000..8f72b5d
--- /dev/null
+++ b/libodb/odb/details/wrapper-p.hxx
@@ -0,0 +1,38 @@
+// file : odb/details/wrapper-p.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WRAPPER_P_HXX
+#define ODB_DETAILS_WRAPPER_P_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/wrapper-traits.hxx>
+
+#include <odb/details/meta/answer.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // GCC doesn't like these to be inside wrapper_p.
+ //
+ template <typename T>
+ meta::no
+ wrapper_p_test (...);
+
+ template <typename T>
+ meta::yes
+ wrapper_p_test (typename wrapper_traits<T>::wrapped_type*);
+
+ template <typename T>
+ struct wrapper_p
+ {
+ static const bool r =
+ sizeof (wrapper_p_test<T> (0)) == sizeof (meta::yes);
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WRAPPER_P_HXX