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