1 //
2 // handler_allocator.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10
11 #ifndef HANDLER_ALLOCATOR_HPP
12 #define HANDLER_ALLOCATOR_HPP
13
14 #include "asio.hpp"
15 #include <boost/aligned_storage.hpp>
16 #include <boost/noncopyable.hpp>
17
18 // Class to manage the memory to be used for handler-based custom allocation.
19 // It contains a single block of memory which may be returned for allocation
20 // requests. If the memory is in use when an allocation request is made, the
21 // allocator delegates allocation to the global heap.
22 class handler_allocator
23 : private boost::noncopyable
24 {
25 public:
handler_allocator()26 handler_allocator()
27 : in_use_(false)
28 {
29 }
30
allocate(std::size_t size)31 void* allocate(std::size_t size)
32 {
33 if (!in_use_ && size < storage_.size)
34 {
35 in_use_ = true;
36 return storage_.address();
37 }
38
39 return ::operator new(size);
40 }
41
deallocate(void * pointer)42 void deallocate(void* pointer)
43 {
44 if (pointer == storage_.address())
45 {
46 in_use_ = false;
47 }
48 else
49 {
50 ::operator delete(pointer);
51 }
52 }
53
54 private:
55 // Storage space used for handler-based custom memory allocation.
56 boost::aligned_storage<1024> storage_;
57
58 // Whether the handler-based custom allocation storage has been used.
59 bool in_use_;
60 };
61
62 // Wrapper class template for handler objects to allow handler memory
63 // allocation to be customised. Calls to operator() are forwarded to the
64 // encapsulated handler.
65 template <typename Handler>
66 class custom_alloc_handler
67 {
68 public:
custom_alloc_handler(handler_allocator & a,Handler h)69 custom_alloc_handler(handler_allocator& a, Handler h)
70 : allocator_(a),
71 handler_(h)
72 {
73 }
74
75 template <typename Arg1>
operator ()(Arg1 arg1)76 void operator()(Arg1 arg1)
77 {
78 handler_(arg1);
79 }
80
81 template <typename Arg1, typename Arg2>
operator ()(Arg1 arg1,Arg2 arg2)82 void operator()(Arg1 arg1, Arg2 arg2)
83 {
84 handler_(arg1, arg2);
85 }
86
asio_handler_allocate(std::size_t size,custom_alloc_handler<Handler> * this_handler)87 friend void* asio_handler_allocate(std::size_t size,
88 custom_alloc_handler<Handler>* this_handler)
89 {
90 return this_handler->allocator_.allocate(size);
91 }
92
asio_handler_deallocate(void * pointer,std::size_t,custom_alloc_handler<Handler> * this_handler)93 friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
94 custom_alloc_handler<Handler>* this_handler)
95 {
96 this_handler->allocator_.deallocate(pointer);
97 }
98
99 private:
100 handler_allocator& allocator_;
101 Handler handler_;
102 };
103
104 // Helper function to wrap a handler object to add custom allocation.
105 template <typename Handler>
make_custom_alloc_handler(handler_allocator & a,Handler h)106 inline custom_alloc_handler<Handler> make_custom_alloc_handler(
107 handler_allocator& a, Handler h)
108 {
109 return custom_alloc_handler<Handler>(a, h);
110 }
111
112 #endif // HANDLER_ALLOCATOR_HPP
113