1//
2// detail/reactor_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_REACTOR_OP_QUEUE_HPP
12#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
13
14
15#include "asio/detail/config.hpp"
16#include "asio/detail/hash_map.hpp"
17#include "asio/detail/noncopyable.hpp"
18#include "asio/detail/op_queue.hpp"
19#include "asio/detail/reactor_op.hpp"
20#include "asio/error.hpp"
21
22#include "asio/detail/push_options.hpp"
23
24namespace asio {
25namespace detail {
26
27template <typename Descriptor>
28class reactor_op_queue
29  : private noncopyable
30{
31public:
32  typedef Descriptor key_type;
33
34  struct mapped_type : op_queue<reactor_op>
35  {
36    mapped_type() {}
37    mapped_type(const mapped_type&) {}
38    void operator=(const mapped_type&) {}
39  };
40
41  typedef typename hash_map<key_type, mapped_type>::value_type value_type;
42  typedef typename hash_map<key_type, mapped_type>::iterator iterator;
43
44  // Constructor.
45  reactor_op_queue()
46    : operations_()
47  {
48  }
49
50  // Obtain iterators to all registered descriptors.
51  iterator begin() { return operations_.begin(); }
52  iterator end() { return operations_.end(); }
53
54  // Add a new operation to the queue. Returns true if this is the only
55  // operation for the given descriptor, in which case the reactor's event
56  // demultiplexing function call may need to be interrupted and restarted.
57  bool enqueue_operation(Descriptor descriptor, reactor_op* op)
58  {
59    std::pair<iterator, bool> entry =
60      operations_.insert(value_type(descriptor, mapped_type()));
61    entry.first->second.push(op);
62    return entry.second;
63  }
64
65  // Cancel all operations associated with the descriptor identified by the
66  // supplied iterator. Any operations pending for the descriptor will be
67  // cancelled. Returns true if any operations were cancelled, in which case
68  // the reactor's event demultiplexing function may need to be interrupted and
69  // restarted.
70  bool cancel_operations(iterator i, op_queue<operation>& ops,
71      const asio::error_code& ec =
72        asio::error::operation_aborted)
73  {
74    if (i != operations_.end())
75    {
76      while (reactor_op* op = i->second.front())
77      {
78        op->ec_ = ec;
79        i->second.pop();
80        ops.push(op);
81      }
82      operations_.erase(i);
83      return true;
84    }
85
86    return false;
87  }
88
89  // Cancel all operations associated with the descriptor. Any operations
90  // pending for the descriptor will be cancelled. Returns true if any
91  // operations were cancelled, in which case the reactor's event
92  // demultiplexing function may need to be interrupted and restarted.
93  bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,
94      const asio::error_code& ec =
95        asio::error::operation_aborted)
96  {
97    return this->cancel_operations(operations_.find(descriptor), ops, ec);
98  }
99
100  // Whether there are no operations in the queue.
101  bool empty() const
102  {
103    return operations_.empty();
104  }
105
106  // Determine whether there are any operations associated with the descriptor.
107  bool has_operation(Descriptor descriptor) const
108  {
109    return operations_.find(descriptor) != operations_.end();
110  }
111
112  // Perform the operations corresponding to the descriptor identified by the
113  // supplied iterator. Returns true if there are still unfinished operations
114  // queued for the descriptor.
115  bool perform_operations(iterator i, op_queue<operation>& ops)
116  {
117    if (i != operations_.end())
118    {
119      while (reactor_op* op = i->second.front())
120      {
121        if (op->perform())
122        {
123          i->second.pop();
124          ops.push(op);
125        }
126        else
127        {
128          return true;
129        }
130      }
131      operations_.erase(i);
132    }
133    return false;
134  }
135
136  // Perform the operations corresponding to the descriptor. Returns true if
137  // there are still unfinished operations queued for the descriptor.
138  bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)
139  {
140    return this->perform_operations(operations_.find(descriptor), ops);
141  }
142
143  // Get all operations owned by the queue.
144  void get_all_operations(op_queue<operation>& ops)
145  {
146    iterator i = operations_.begin();
147    while (i != operations_.end())
148    {
149      iterator op_iter = i++;
150      ops.push(op_iter->second);
151      operations_.erase(op_iter);
152    }
153  }
154
155private:
156  // The operations that are currently executing asynchronously.
157  hash_map<key_type, mapped_type> operations_;
158};
159
160} // namespace detail
161} // namespace asio
162
163#include "asio/detail/pop_options.hpp"
164
165#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
166