Add first cut of new handler_traits.
diff --git a/asio/include/Makefile.am b/asio/include/Makefile.am index 4b81b3d..37679d8 100644 --- a/asio/include/Makefile.am +++ b/asio/include/Makefile.am
@@ -58,6 +58,7 @@ asio/detail/handler_alloc_helpers.hpp \ asio/detail/handler_invoke_helpers.hpp \ asio/detail/handler_tracking.hpp \ + asio/detail/handler_traits.hpp \ asio/detail/handler_type_requirements.hpp \ asio/detail/hash_map.hpp \ asio/detail/impl/descriptor_ops.ipp \ @@ -219,6 +220,7 @@ asio/error.hpp \ asio/handler_alloc_hook.hpp \ asio/handler_invoke_hook.hpp \ + asio/handler_traits.hpp \ asio.hpp \ asio/impl/connect.hpp \ asio/impl/error_code.ipp \
diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp index 398fbeb..4182bad 100644 --- a/asio/include/asio.hpp +++ b/asio/include/asio.hpp
@@ -44,6 +44,7 @@ #include "asio/error_code.hpp" #include "asio/handler_alloc_hook.hpp" #include "asio/handler_invoke_hook.hpp" +#include "asio/handler_traits.hpp" #include "asio/io_service.hpp" #include "asio/ip/address.hpp" #include "asio/ip/address_v4.hpp"
diff --git a/asio/include/asio/detail/completion_handler.hpp b/asio/include/asio/detail/completion_handler.hpp index 628b712..2a2aa79 100644 --- a/asio/include/asio/detail/completion_handler.hpp +++ b/asio/include/asio/detail/completion_handler.hpp
@@ -17,9 +17,8 @@ #include "asio/detail/config.hpp" #include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" +#include "asio/handler_traits.hpp" #include "asio/detail/push_options.hpp" @@ -62,7 +61,8 @@ { asio::detail::fenced_block b; ASIO_HANDLER_INVOCATION_BEGIN(()); - asio_handler_invoke_helpers::invoke(handler, handler); + ptr::traits_type::get_invoker(handler).invoke( + ASIO_MOVE_CAST(Handler)(handler)); ASIO_HANDLER_INVOCATION_END; } }
diff --git a/asio/include/asio/detail/deadline_timer_service.hpp b/asio/include/asio/detail/deadline_timer_service.hpp index 6eb0434..3cca342 100644 --- a/asio/include/asio/detail/deadline_timer_service.hpp +++ b/asio/include/asio/detail/deadline_timer_service.hpp
@@ -182,8 +182,7 @@ // Allocate and construct an operation to wrap the handler. typedef wait_handler<Handler> op; typename op::ptr p = { boost::addressof(handler), - asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); impl.might_have_pending_waits = true;
diff --git a/asio/include/asio/detail/handler_alloc_helpers.hpp b/asio/include/asio/detail/handler_alloc_helpers.hpp index 9ae80de..0f70626 100644 --- a/asio/include/asio/detail/handler_alloc_helpers.hpp +++ b/asio/include/asio/detail/handler_alloc_helpers.hpp
@@ -17,6 +17,7 @@ #include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> +#include <boost/limits.hpp> #include <boost/utility/addressof.hpp> #include "asio/detail/noncopyable.hpp" #include "asio/handler_alloc_hook.hpp" @@ -54,31 +55,131 @@ } // namespace asio_handler_alloc_helpers -#define ASIO_DEFINE_HANDLER_PTR(op) \ - struct ptr \ - { \ - Handler* h; \ - void* v; \ - op* p; \ - ~ptr() \ - { \ - reset(); \ - } \ - void reset() \ - { \ - if (p) \ - { \ - p->~op(); \ - p = 0; \ - } \ - if (v) \ - { \ - asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ - v = 0; \ - } \ - } \ - } \ - /**/ +namespace asio { +namespace detail { + +// The default allocator simply forwards to the old-style allocation hook. +template <typename T, typename Context> +class default_handler_allocator +{ +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template <typename U> + struct rebind + { + typedef default_handler_allocator<U, Context> other; + }; + + explicit default_handler_allocator(Context* context) + : context_(context) + { + } + + template <typename U> + default_handler_allocator(const default_handler_allocator<U, Context>& other) + : context_(other.context_) + { + } + + static pointer address(reference r) + { + return &r; + } + + static const_pointer address(const_reference r) + { + return &r; + } + + static size_type max_size() + { + return (std::numeric_limits<size_type>::max)(); + } + + static void construct(const pointer p, const value_type& v) + { + new (p) T(v); + } + + static void destroy(const pointer p) + { + p->~T(); + } + + bool operator==(const default_handler_allocator& other) const + { + return context_ == other.context_; + } + + bool operator!=(const default_handler_allocator& other) const + { + return context_ != other.context_; + } + + pointer allocate(size_type n, const void* = 0) + { + return static_cast<pointer>( + asio_handler_alloc_helpers::allocate(n * sizeof(T), *context_)); + } + + void deallocate(pointer p, size_type n) + { + return asio_handler_alloc_helpers::deallocate(p, n * sizeof(T), *context_); + } + +//private: + Context* context_; +}; + +// The default allocator specialised for void. +template <typename Context> +class default_handler_allocator<void, Context> +{ +public: + typedef void value_type; + typedef void* pointer; + typedef const void* const_pointer; + + template <typename U> + struct rebind + { + typedef default_handler_allocator<U, Context> other; + }; + + explicit default_handler_allocator(Context* context) + : context_(context) + { + } + + template <typename U> + default_handler_allocator(const default_handler_allocator<U, Context>& other) + : context_(other.context_) + { + } + + bool operator==(const default_handler_allocator& other) const + { + return context_ == other.context_; + } + + bool operator!=(const default_handler_allocator& other) const + { + return context_ != other.context_; + } + +//private: + Context* context_; +}; + +} // namespace detail +} // namespace asio #include "asio/detail/pop_options.hpp"
diff --git a/asio/include/asio/detail/handler_invoke_helpers.hpp b/asio/include/asio/detail/handler_invoke_helpers.hpp index 5b122d9..2b30079 100644 --- a/asio/include/asio/detail/handler_invoke_helpers.hpp +++ b/asio/include/asio/detail/handler_invoke_helpers.hpp
@@ -42,6 +42,32 @@ } // namespace asio_handler_invoke_helpers +namespace asio { +namespace detail { + +// The default invoker simply forwards to the old-style invocation hook. +template <typename Context> +class default_handler_invoker +{ +public: + explicit default_handler_invoker(Context* context) + : context_(context) + { + } + + template <typename Function> + void invoke(Function function) + { + asio_handler_invoke_helpers::invoke(function, *context_); + } + +private: + Context* context_; +}; + +} // namespace detail +} // namespace asio + #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
diff --git a/asio/include/asio/detail/handler_traits.hpp b/asio/include/asio/detail/handler_traits.hpp new file mode 100644 index 0000000..778664c --- /dev/null +++ b/asio/include/asio/detail/handler_traits.hpp
@@ -0,0 +1,160 @@ +// +// detail/handler_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_TRAITS_HPP +#define ASIO_DETAIL_HANDLER_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Type trait for determining whether a handler has an invoker_type typedef. + +char (&invoker_type_test(...))[2]; + +template <typename T> char invoker_type_test( + T*, typename T::invoker_type* = 0); + +template <typename T> +struct has_invoker_type +{ + enum { value = (sizeof((invoker_type_test)(static_cast<T*>(0))) == 1) }; +}; + +// Type trait for determining whether a handler has an allocator_type typedef. + +char (&allocator_type_test(...))[2]; + +template <typename T> char allocator_type_test( + T*, typename T::allocator_type* = 0); + +template <typename T> +struct has_allocator_type +{ + enum { value = (sizeof((allocator_type_test)(static_cast<T*>(0))) == 1) }; +}; + +// Traits base class for selectively forwarding the invoker typedef and +// accessor function to the handler class. + +template <typename Handler, bool HasInvoker = has_invoker_type<Handler>::value> +struct handler_traits_invoker; + +template <typename Handler> +struct handler_traits_invoker<Handler, true> +{ + typedef typename Handler::invoker_type invoker_type; + + static invoker_type get_invoker(Handler& handler) + { + return handler.get_invoker(); + } +}; + +template <typename Handler> +struct handler_traits_invoker<Handler, false> +{ + typedef default_handler_invoker<Handler> invoker_type; + + static invoker_type get_invoker(Handler& handler) + { + return invoker_type(boost::addressof(handler)); + } +}; + +// Traits base class for selectively forwarding the allocator typedef and +// accessor function to the handler class. + +template <typename Handler, bool HasAllocator = has_allocator_type<Handler>::value> +struct handler_traits_allocator; + +template <typename Handler> +struct handler_traits_allocator<Handler, true> +{ + typedef typename Handler::allocator_type allocator_type; + + static allocator_type get_allocator(Handler& handler) + { + return handler.get_allocator(); + } +}; + +template <typename Handler> +struct handler_traits_allocator<Handler, false> +{ + typedef default_handler_allocator<void, Handler> allocator_type; + + static allocator_type get_allocator(Handler& handler) + { + return allocator_type(boost::addressof(handler)); + } +}; + +// The default handler traits. + +template <typename Handler> +struct handler_traits : + handler_traits_invoker<Handler>, + handler_traits_allocator<Handler> +{ +}; + +} // namespace detail +} // namespace asio + +#define ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + typedef asio::handler_traits<Handler> traits_type; \ + typedef typename traits_type::allocator_type any_allocator_type; \ + typedef typename any_allocator_type::template rebind< \ + op>::other allocator_type; \ + Handler* h; \ + void* v; \ + op* p; \ + static op* allocate(Handler& handler) \ + { \ + allocator_type allocator = traits_type::get_allocator(handler); \ + return allocator.allocate(1); \ + } \ + ~ptr() \ + { \ + reset(); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + allocator_type allocator = traits_type::get_allocator(*h); \ + allocator.deallocate(static_cast<op*>(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_TRAITS_HPP
diff --git a/asio/include/asio/detail/impl/task_io_service.hpp b/asio/include/asio/detail/impl/task_io_service.hpp index bd0cd25..59bb96e 100644 --- a/asio/include/asio/detail/impl/task_io_service.hpp +++ b/asio/include/asio/detail/impl/task_io_service.hpp
@@ -18,8 +18,7 @@ #include "asio/detail/call_stack.hpp" #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_traits.hpp" #include "asio/detail/push_options.hpp" @@ -39,8 +38,7 @@ // Allocate and construct an operation to wrap the handler. typedef completion_handler<Handler> op; typename op::ptr p = { boost::addressof(handler), - asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); ASIO_HANDLER_CREATION((p.p, "io_service", this, "dispatch")); @@ -56,8 +54,7 @@ // Allocate and construct an operation to wrap the handler. typedef completion_handler<Handler> op; typename op::ptr p = { boost::addressof(handler), - asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); ASIO_HANDLER_CREATION((p.p, "io_service", this, "post"));
diff --git a/asio/include/asio/detail/wait_handler.hpp b/asio/include/asio/detail/wait_handler.hpp index a5e152c..56eee10 100644 --- a/asio/include/asio/detail/wait_handler.hpp +++ b/asio/include/asio/detail/wait_handler.hpp
@@ -32,9 +32,9 @@ public: ASIO_DEFINE_HANDLER_PTR(wait_handler); - wait_handler(Handler h) + wait_handler(Handler& h) : timer_op(&wait_handler::do_complete), - handler_(h) + handler_(ASIO_MOVE_CAST(Handler)(h)) { } @@ -53,8 +53,8 @@ // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(h->handler_, h->ec_); + typedef detail::binder1<Handler, asio::error_code> binder; + binder handler(h->handler_, h->ec_); p.h = boost::addressof(handler.handler_); p.reset(); @@ -63,7 +63,8 @@ { asio::detail::fenced_block b; ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - asio_handler_invoke_helpers::invoke(handler, handler.handler_); + ptr::traits_type::get_invoker(handler.handler_).invoke( + ASIO_MOVE_CAST(binder)(handler)); ASIO_HANDLER_INVOCATION_END; } }
diff --git a/asio/include/asio/handler_traits.hpp b/asio/include/asio/handler_traits.hpp new file mode 100644 index 0000000..3b81ef6 --- /dev/null +++ b/asio/include/asio/handler_traits.hpp
@@ -0,0 +1,35 @@ +// +// handler_traits.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_HANDLER_TRAITS_HPP +#define ASIO_HANDLER_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/handler_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Handler> +struct handler_traits + : asio::detail::handler_traits<Handler> +{ +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_HANDLER_TRAITS_HPP