1 //
2 // detail/op_queue.hpp
3 // ~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 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 ASIO_DETAIL_OP_QUEUE_HPP
12 #define ASIO_DETAIL_OP_QUEUE_HPP
13 
14 
15 #include "asio/detail/noncopyable.hpp"
16 
17 #include "asio/detail/push_options.hpp"
18 
19 namespace asio {
20 namespace detail {
21 
22 template <typename Operation>
23 class op_queue;
24 
25 class op_queue_access
26 {
27 public:
28   template <typename Operation>
next(Operation * o)29   static Operation* next(Operation* o)
30   {
31     return static_cast<Operation*>(o->next_);
32   }
33 
34   template <typename Operation1, typename Operation2>
next(Operation1 * & o1,Operation2 * o2)35   static void next(Operation1*& o1, Operation2* o2)
36   {
37     o1->next_ = o2;
38   }
39 
40   template <typename Operation>
destroy(Operation * o)41   static void destroy(Operation* o)
42   {
43     o->destroy();
44   }
45 
46   template <typename Operation>
front(op_queue<Operation> & q)47   static Operation*& front(op_queue<Operation>& q)
48   {
49     return q.front_;
50   }
51 
52   template <typename Operation>
back(op_queue<Operation> & q)53   static Operation*& back(op_queue<Operation>& q)
54   {
55     return q.back_;
56   }
57 };
58 
59 template <typename Operation>
60 class op_queue
61   : private noncopyable
62 {
63 public:
64   // Constructor.
op_queue()65   op_queue()
66     : front_(0),
67       back_(0)
68   {
69   }
70 
71   // Destructor destroys all operations.
~op_queue()72   ~op_queue()
73   {
74     while (Operation* op = front_)
75     {
76       pop();
77       op_queue_access::destroy(op);
78     }
79   }
80 
81   // Get the operation at the front of the queue.
front()82   Operation* front()
83   {
84     return front_;
85   }
86 
87   // Pop an operation from the front of the queue.
pop()88   void pop()
89   {
90     if (front_)
91     {
92       Operation* tmp = front_;
93       front_ = op_queue_access::next(front_);
94       if (front_ == 0)
95         back_ = 0;
96       op_queue_access::next(tmp, static_cast<Operation*>(0));
97     }
98   }
99 
100   // Push an operation on to the back of the queue.
push(Operation * h)101   void push(Operation* h)
102   {
103     op_queue_access::next(h, static_cast<Operation*>(0));
104     if (back_)
105     {
106       op_queue_access::next(back_, h);
107       back_ = h;
108     }
109     else
110     {
111       front_ = back_ = h;
112     }
113   }
114 
115   // Push all operations from another queue on to the back of the queue. The
116   // source queue may contain operations of a derived type.
117   template <typename OtherOperation>
push(op_queue<OtherOperation> & q)118   void push(op_queue<OtherOperation>& q)
119   {
120     if (Operation* other_front = op_queue_access::front(q))
121     {
122       if (back_)
123         op_queue_access::next(back_, other_front);
124       else
125         front_ = other_front;
126       back_ = op_queue_access::back(q);
127       op_queue_access::front(q) = 0;
128       op_queue_access::back(q) = 0;
129     }
130   }
131 
132   // Whether the queue is empty.
empty() const133   bool empty() const
134   {
135     return front_ == 0;
136   }
137 
138 private:
139   friend class op_queue_access;
140 
141   // The front of the queue.
142   Operation* front_;
143 
144   // The back of the queue.
145   Operation* back_;
146 };
147 
148 } // namespace detail
149 } // namespace asio
150 
151 #include "asio/detail/pop_options.hpp"
152 
153 #endif // ASIO_DETAIL_OP_QUEUE_HPP
154