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
19namespace asio {
20namespace detail {
21
22template <typename Operation>
23class op_queue;
24
25class op_queue_access
26{
27public:
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
59template <typename Operation>
60class op_queue
61  : private noncopyable
62{
63public:
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
138private:
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