5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
15 #include <type_traits>
17 #include <boost/asio.hpp>
19 using boost::asio::ip::tcp
;
21 // Class to manage the memory to be used for handler-based custom allocation.
22 // It contains a single block of memory which may be returned for allocation
23 // requests. If the memory is in use when an allocation request is made, the
24 // allocator delegates allocation to the global heap.
33 handler_memory(const handler_memory
&) = delete;
34 handler_memory
& operator=(const handler_memory
&) = delete;
36 void* allocate(std::size_t size
)
38 if (!in_use_
&& size
< sizeof(storage_
))
45 return ::operator new(size
);
49 void deallocate(void* pointer
)
51 if (pointer
== &storage_
)
57 ::operator delete(pointer
);
62 // Storage space used for handler-based custom memory allocation.
63 typename
std::aligned_storage
<1024>::type storage_
;
65 // Whether the handler-based custom allocation storage has been used.
69 // The allocator to be associated with the handler objects. This allocator only
70 // needs to satisfy the C++11 minimal allocator requirements.
72 class handler_allocator
77 explicit handler_allocator(handler_memory
& mem
)
83 handler_allocator(const handler_allocator
<U
>& other
) noexcept
84 : memory_(other
.memory_
)
88 bool operator==(const handler_allocator
& other
) const noexcept
90 return &memory_
== &other
.memory_
;
93 bool operator!=(const handler_allocator
& other
) const noexcept
95 return &memory_
!= &other
.memory_
;
98 T
* allocate(std::size_t n
) const
100 return static_cast<T
*>(memory_
.allocate(sizeof(T
) * n
));
103 void deallocate(T
* p
, std::size_t /*n*/) const
105 return memory_
.deallocate(p
);
109 template <typename
> friend class handler_allocator
;
111 // The underlying memory.
112 handler_memory
& memory_
;
115 // Wrapper class template for handler objects to allow handler memory
116 // allocation to be customised. The allocator_type type and get_allocator()
117 // member function are used by the asynchronous operations to obtain the
118 // allocator. Calls to operator() are forwarded to the encapsulated handler.
119 template <typename Handler
>
120 class custom_alloc_handler
123 using allocator_type
= handler_allocator
<Handler
>;
125 custom_alloc_handler(handler_memory
& m
, Handler h
)
131 allocator_type
get_allocator() const noexcept
133 return allocator_type(memory_
);
136 template <typename
...Args
>
137 void operator()(Args
&&... args
)
139 handler_(std::forward
<Args
>(args
)...);
143 handler_memory
& memory_
;
147 // Helper function to wrap a handler object to add custom allocation.
148 template <typename Handler
>
149 inline custom_alloc_handler
<Handler
> make_custom_alloc_handler(
150 handler_memory
& m
, Handler h
)
152 return custom_alloc_handler
<Handler
>(m
, h
);
156 : public std::enable_shared_from_this
<session
>
159 session(tcp::socket socket
)
160 : socket_(std::move(socket
))
172 auto self(shared_from_this());
173 socket_
.async_read_some(boost::asio::buffer(data_
),
174 make_custom_alloc_handler(handler_memory_
,
175 [this, self
](boost::system::error_code ec
, std::size_t length
)
184 void do_write(std::size_t length
)
186 auto self(shared_from_this());
187 boost::asio::async_write(socket_
, boost::asio::buffer(data_
, length
),
188 make_custom_alloc_handler(handler_memory_
,
189 [this, self
](boost::system::error_code ec
, std::size_t /*length*/)
198 // The socket used to communicate with the client.
201 // Buffer used to store data received from the client.
202 std::array
<char, 1024> data_
;
204 // The memory to use for handler-based custom memory allocation.
205 handler_memory handler_memory_
;
211 server(boost::asio::io_context
& io_context
, short port
)
212 : acceptor_(io_context
, tcp::endpoint(tcp::v4(), port
))
220 acceptor_
.async_accept(
221 [this](boost::system::error_code ec
, tcp::socket socket
)
225 std::make_shared
<session
>(std::move(socket
))->start();
232 tcp::acceptor acceptor_
;
235 int main(int argc
, char* argv
[])
241 std::cerr
<< "Usage: server <port>\n";
245 boost::asio::io_context io_context
;
246 server
s(io_context
, std::atoi(argv
[1]));
249 catch (std::exception
& e
)
251 std::cerr
<< "Exception: " << e
.what() << "\n";