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> 29 static Operation* next(Operation* o) 30 { 31 return static_cast<Operation*>(o->next_); 32 } 33 34 template <typename Operation1, typename Operation2> 35 static void next(Operation1*& o1, Operation2* o2) 36 { 37 o1->next_ = o2; 38 } 39 40 template <typename Operation> 41 static void destroy(Operation* o) 42 { 43 o->destroy(); 44 } 45 46 template <typename Operation> 47 static Operation*& front(op_queue<Operation>& q) 48 { 49 return q.front_; 50 } 51 52 template <typename Operation> 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. 65 op_queue() 66 : front_(0), 67 back_(0) 68 { 69 } 70 71 // Destructor destroys all operations. 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. 82 Operation* front() 83 { 84 return front_; 85 } 86 87 // Pop an operation from the front of the queue. 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. 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> 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. 133 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