diff options
Diffstat (limited to 'libodb/odb/details')
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 |