summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/src/examples/cpp11
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/src/examples/cpp11')
-rw-r--r--3rdparty/asio/src/examples/cpp11/Makefile.am92
-rw-r--r--3rdparty/asio/src/examples/cpp11/allocation/.gitignore10
-rw-r--r--3rdparty/asio/src/examples/cpp11/allocation/server.cpp213
-rw-r--r--3rdparty/asio/src/examples/cpp11/buffers/.gitignore10
-rw-r--r--3rdparty/asio/src/examples/cpp11/buffers/reference_counted.cpp121
-rw-r--r--3rdparty/asio/src/examples/cpp11/chat/.gitignore11
-rw-r--r--3rdparty/asio/src/examples/cpp11/chat/chat_client.cpp167
-rw-r--r--3rdparty/asio/src/examples/cpp11/chat/chat_message.hpp91
-rw-r--r--3rdparty/asio/src/examples/cpp11/chat/chat_server.cpp227
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/.gitignore11
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp114
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/async_udp_echo_server.cpp82
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp55
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp74
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_client.cpp58
-rw-r--r--3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_server.cpp52
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/.gitignore5
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/actor.cpp286
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/bank_account_1.cpp54
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/bank_account_2.cpp54
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/fork_join.cpp327
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/pipeline.cpp298
-rw-r--r--3rdparty/asio/src/examples/cpp11/executors/priority_scheduler.cpp168
-rw-r--r--3rdparty/asio/src/examples/cpp11/futures/.gitignore11
-rw-r--r--3rdparty/asio/src/examples/cpp11/futures/daytime_client.cpp94
-rw-r--r--3rdparty/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp201
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/.gitignore11
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/connection.cpp94
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/connection.hpp79
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/connection_manager.cpp40
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/connection_manager.hpp48
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/header.hpp28
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/main.cpp43
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/mime_types.cpp45
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/mime_types.hpp27
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/reply.cpp255
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/reply.hpp64
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/request.hpp34
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/request_handler.cpp121
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/request_handler.hpp47
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/request_parser.cpp315
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/request_parser.hpp96
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/server.cpp94
-rw-r--r--3rdparty/asio/src/examples/cpp11/http/server/server.hpp64
-rw-r--r--3rdparty/asio/src/examples/cpp11/iostreams/.gitignore11
-rw-r--r--3rdparty/asio/src/examples/cpp11/iostreams/http_client.cpp91
-rw-r--r--3rdparty/asio/src/examples/cpp11/spawn/.gitignore12
-rw-r--r--3rdparty/asio/src/examples/cpp11/spawn/echo_server.cpp108
-rw-r--r--3rdparty/asio/src/examples/cpp11/spawn/parallel_grep.cpp84
49 files changed, 4697 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp11/Makefile.am b/3rdparty/asio/src/examples/cpp11/Makefile.am
new file mode 100644
index 00000000000..182c711229f
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/Makefile.am
@@ -0,0 +1,92 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+if SEPARATE_COMPILATION
+noinst_LIBRARIES = libasio.a
+libasio_a_SOURCES = ../../asio.cpp
+if HAVE_OPENSSL
+libasio_a_SOURCES += ../../asio_ssl.cpp
+endif
+LDADD = libasio.a
+endif
+
+noinst_PROGRAMS = \
+ allocation/server \
+ buffers/reference_counted \
+ chat/chat_client \
+ chat/chat_server \
+ echo/async_tcp_echo_server \
+ echo/async_udp_echo_server \
+ echo/blocking_tcp_echo_client \
+ echo/blocking_tcp_echo_server \
+ echo/blocking_udp_echo_client \
+ echo/blocking_udp_echo_server \
+ executors/actor \
+ executors/bank_account_1 \
+ executors/bank_account_2 \
+ executors/fork_join \
+ executors/pipeline \
+ executors/priority_scheduler \
+ futures/daytime_client \
+ http/server/http_server \
+ iostreams/http_client
+
+if HAVE_BOOST_COROUTINE
+noinst_PROGRAMS += \
+ spawn/echo_server \
+ spawn/parallel_grep
+endif
+
+noinst_HEADERS = \
+ chat/chat_message.hpp
+
+AM_CXXFLAGS = -I$(srcdir)/../../../include
+
+allocation_server_SOURCES = allocation/server.cpp
+buffers_reference_counted_SOURCES = buffers/reference_counted.cpp
+chat_chat_client_SOURCES = chat/chat_client.cpp
+chat_chat_server_SOURCES = chat/chat_server.cpp
+echo_async_tcp_echo_server_SOURCES = echo/async_tcp_echo_server.cpp
+echo_async_udp_echo_server_SOURCES = echo/async_udp_echo_server.cpp
+echo_blocking_tcp_echo_client_SOURCES = echo/blocking_tcp_echo_client.cpp
+echo_blocking_tcp_echo_server_SOURCES = echo/blocking_tcp_echo_server.cpp
+echo_blocking_udp_echo_client_SOURCES = echo/blocking_udp_echo_client.cpp
+echo_blocking_udp_echo_server_SOURCES = echo/blocking_udp_echo_server.cpp
+executors_actor_SOURCES = executors/actor.cpp
+executors_bank_account_1_SOURCES = executors/bank_account_1.cpp
+executors_bank_account_2_SOURCES = executors/bank_account_2.cpp
+executors_fork_join_SOURCES = executors/fork_join.cpp
+executors_pipeline_SOURCES = executors/pipeline.cpp
+executors_priority_scheduler_SOURCES = executors/priority_scheduler.cpp
+futures_daytime_client_SOURCES = futures/daytime_client.cpp
+http_server_http_server_SOURCES = \
+ http/server/connection.cpp \
+ http/server/connection_manager.cpp \
+ http/server/main.cpp \
+ http/server/mime_types.cpp \
+ http/server/reply.cpp \
+ http/server/request_handler.cpp \
+ http/server/request_parser.cpp \
+ http/server/server.cpp
+iostreams_http_client_SOURCES = iostreams/http_client.cpp
+
+if HAVE_BOOST_COROUTINE
+spawn_echo_server_SOURCES = spawn/echo_server.cpp
+spawn_echo_server_LDADD = $(LDADD) -lboost_coroutine -lboost_context -lboost_thread -lboost_chrono -lboost_system
+spawn_parallel_grep_SOURCES = spawn/parallel_grep.cpp
+spawn_parallel_grep_LDADD = $(LDADD) -lboost_coroutine -lboost_context -lboost_thread -lboost_chrono -lboost_system
+endif
+
+EXTRA_DIST = \
+ handler_tracking/custom_tracking.hpp \
+ http/server/connection.hpp \
+ http/server/connection_manager.hpp \
+ http/server/header.hpp \
+ http/server/mime_types.hpp \
+ http/server/reply.hpp \
+ http/server/request.hpp \
+ http/server/request_handler.hpp \
+ http/server/request_parser.hpp \
+ http/server/server.hpp
+
+MAINTAINERCLEANFILES = \
+ $(srcdir)/Makefile.in
diff --git a/3rdparty/asio/src/examples/cpp11/allocation/.gitignore b/3rdparty/asio/src/examples/cpp11/allocation/.gitignore
new file mode 100644
index 00000000000..180ba886e58
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/allocation/.gitignore
@@ -0,0 +1,10 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+server
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/allocation/server.cpp b/3rdparty/asio/src/examples/cpp11/allocation/server.cpp
new file mode 100644
index 00000000000..cbcbe76fe68
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/allocation/server.cpp
@@ -0,0 +1,213 @@
+//
+// server.cpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <array>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include "asio.hpp"
+
+using asio::ip::tcp;
+
+// Class to manage the memory to be used for handler-based custom allocation.
+// It contains a single block of memory which may be returned for allocation
+// requests. If the memory is in use when an allocation request is made, the
+// allocator delegates allocation to the global heap.
+class handler_allocator
+{
+public:
+ handler_allocator()
+ : in_use_(false)
+ {
+ }
+
+ handler_allocator(const handler_allocator&) = delete;
+ handler_allocator& operator=(const handler_allocator&) = delete;
+
+ void* allocate(std::size_t size)
+ {
+ if (!in_use_ && size < sizeof(storage_))
+ {
+ in_use_ = true;
+ return &storage_;
+ }
+ else
+ {
+ return ::operator new(size);
+ }
+ }
+
+ void deallocate(void* pointer)
+ {
+ if (pointer == &storage_)
+ {
+ in_use_ = false;
+ }
+ else
+ {
+ ::operator delete(pointer);
+ }
+ }
+
+private:
+ // Storage space used for handler-based custom memory allocation.
+ typename std::aligned_storage<1024>::type storage_;
+
+ // Whether the handler-based custom allocation storage has been used.
+ bool in_use_;
+};
+
+// Wrapper class template for handler objects to allow handler memory
+// allocation to be customised. Calls to operator() are forwarded to the
+// encapsulated handler.
+template <typename Handler>
+class custom_alloc_handler
+{
+public:
+ custom_alloc_handler(handler_allocator& a, Handler h)
+ : allocator_(a),
+ handler_(h)
+ {
+ }
+
+ template <typename ...Args>
+ void operator()(Args&&... args)
+ {
+ handler_(std::forward<Args>(args)...);
+ }
+
+ friend void* asio_handler_allocate(std::size_t size,
+ custom_alloc_handler<Handler>* this_handler)
+ {
+ return this_handler->allocator_.allocate(size);
+ }
+
+ friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
+ custom_alloc_handler<Handler>* this_handler)
+ {
+ this_handler->allocator_.deallocate(pointer);
+ }
+
+private:
+ handler_allocator& allocator_;
+ Handler handler_;
+};
+
+// Helper function to wrap a handler object to add custom allocation.
+template <typename Handler>
+inline custom_alloc_handler<Handler> make_custom_alloc_handler(
+ handler_allocator& a, Handler h)
+{
+ return custom_alloc_handler<Handler>(a, h);
+}
+
+class session
+ : public std::enable_shared_from_this<session>
+{
+public:
+ session(tcp::socket socket)
+ : socket_(std::move(socket))
+ {
+ }
+
+ void start()
+ {
+ do_read();
+ }
+
+private:
+ void do_read()
+ {
+ auto self(shared_from_this());
+ socket_.async_read_some(asio::buffer(data_),
+ make_custom_alloc_handler(allocator_,
+ [this, self](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ do_write(length);
+ }
+ }));
+ }
+
+ void do_write(std::size_t length)
+ {
+ auto self(shared_from_this());
+ asio::async_write(socket_, asio::buffer(data_, length),
+ make_custom_alloc_handler(allocator_,
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ do_read();
+ }
+ }));
+ }
+
+ // The socket used to communicate with the client.
+ tcp::socket socket_;
+
+ // Buffer used to store data received from the client.
+ std::array<char, 1024> data_;
+
+ // The allocator to use for handler-based custom memory allocation.
+ handler_allocator allocator_;
+};
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<session>(std::move(socket))->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+ server s(io_context, std::atoi(argv[1]));
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/buffers/.gitignore b/3rdparty/asio/src/examples/cpp11/buffers/.gitignore
new file mode 100644
index 00000000000..abe68c665f5
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/buffers/.gitignore
@@ -0,0 +1,10 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+reference_counted
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/buffers/reference_counted.cpp b/3rdparty/asio/src/examples/cpp11/buffers/reference_counted.cpp
new file mode 100644
index 00000000000..34fe9090dfd
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/buffers/reference_counted.cpp
@@ -0,0 +1,121 @@
+//
+// reference_counted.cpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <asio.hpp>
+#include <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
+
+using asio::ip::tcp;
+
+// A reference-counted non-modifiable buffer class.
+class shared_const_buffer
+{
+public:
+ // Construct from a std::string.
+ explicit shared_const_buffer(const std::string& data)
+ : data_(new std::vector<char>(data.begin(), data.end())),
+ buffer_(asio::buffer(*data_))
+ {
+ }
+
+ // Implement the ConstBufferSequence requirements.
+ typedef asio::const_buffer value_type;
+ typedef const asio::const_buffer* const_iterator;
+ const asio::const_buffer* begin() const { return &buffer_; }
+ const asio::const_buffer* end() const { return &buffer_ + 1; }
+
+private:
+ std::shared_ptr<std::vector<char> > data_;
+ asio::const_buffer buffer_;
+};
+
+class session
+ : public std::enable_shared_from_this<session>
+{
+public:
+ session(tcp::socket socket)
+ : socket_(std::move(socket))
+ {
+ }
+
+ void start()
+ {
+ do_write();
+ }
+
+private:
+ void do_write()
+ {
+ std::time_t now = std::time(0);
+ shared_const_buffer buffer(std::ctime(&now));
+
+ auto self(shared_from_this());
+ asio::async_write(socket_, buffer,
+ [this, self](std::error_code /*ec*/, std::size_t /*length*/)
+ {
+ });
+ }
+
+ // The socket used to communicate with the client.
+ tcp::socket socket_;
+};
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<session>(std::move(socket))->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: reference_counted <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(argv[1]));
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/chat/.gitignore b/3rdparty/asio/src/examples/cpp11/chat/.gitignore
new file mode 100644
index 00000000000..0882fa6ced3
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/chat/.gitignore
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+*_server
+*_client
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/chat/chat_client.cpp b/3rdparty/asio/src/examples/cpp11/chat/chat_client.cpp
new file mode 100644
index 00000000000..e672a022d04
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/chat/chat_client.cpp
@@ -0,0 +1,167 @@
+//
+// chat_client.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <thread>
+#include "asio.hpp"
+#include "chat_message.hpp"
+
+using asio::ip::tcp;
+
+typedef std::deque<chat_message> chat_message_queue;
+
+class chat_client
+{
+public:
+ chat_client(asio::io_context& io_context,
+ const tcp::resolver::results_type& endpoints)
+ : io_context_(io_context),
+ socket_(io_context)
+ {
+ do_connect(endpoints);
+ }
+
+ void write(const chat_message& msg)
+ {
+ asio::post(io_context_,
+ [this, msg]()
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ do_write();
+ }
+ });
+ }
+
+ void close()
+ {
+ asio::post(io_context_, [this]() { socket_.close(); });
+ }
+
+private:
+ void do_connect(const tcp::resolver::results_type& endpoints)
+ {
+ asio::async_connect(socket_, endpoints,
+ [this](std::error_code ec, tcp::endpoint)
+ {
+ if (!ec)
+ {
+ do_read_header();
+ }
+ });
+ }
+
+ void do_read_header()
+ {
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.data(), chat_message::header_length),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec && read_msg_.decode_header())
+ {
+ do_read_body();
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+ void do_read_body()
+ {
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ std::cout.write(read_msg_.body(), read_msg_.body_length());
+ std::cout << "\n";
+ do_read_header();
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+ void do_write()
+ {
+ asio::async_write(socket_,
+ asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ do_write();
+ }
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+private:
+ asio::io_context& io_context_;
+ tcp::socket socket_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cerr << "Usage: chat_client <host> <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ tcp::resolver resolver(io_context);
+ auto endpoints = resolver.resolve(argv[1], argv[2]);
+ chat_client c(io_context, endpoints);
+
+ std::thread t([&io_context](){ io_context.run(); });
+
+ char line[chat_message::max_body_length + 1];
+ while (std::cin.getline(line, chat_message::max_body_length + 1))
+ {
+ chat_message msg;
+ msg.body_length(std::strlen(line));
+ std::memcpy(msg.body(), line, msg.body_length());
+ msg.encode_header();
+ c.write(msg);
+ }
+
+ c.close();
+ t.join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/chat/chat_message.hpp b/3rdparty/asio/src/examples/cpp11/chat/chat_message.hpp
new file mode 100644
index 00000000000..f6e949bf2e2
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/chat/chat_message.hpp
@@ -0,0 +1,91 @@
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+ enum { header_length = 4 };
+ enum { max_body_length = 512 };
+
+ chat_message()
+ : body_length_(0)
+ {
+ }
+
+ const char* data() const
+ {
+ return data_;
+ }
+
+ char* data()
+ {
+ return data_;
+ }
+
+ std::size_t length() const
+ {
+ return header_length + body_length_;
+ }
+
+ const char* body() const
+ {
+ return data_ + header_length;
+ }
+
+ char* body()
+ {
+ return data_ + header_length;
+ }
+
+ std::size_t body_length() const
+ {
+ return body_length_;
+ }
+
+ void body_length(std::size_t new_length)
+ {
+ body_length_ = new_length;
+ if (body_length_ > max_body_length)
+ body_length_ = max_body_length;
+ }
+
+ bool decode_header()
+ {
+ char header[header_length + 1] = "";
+ std::strncat(header, data_, header_length);
+ body_length_ = std::atoi(header);
+ if (body_length_ > max_body_length)
+ {
+ body_length_ = 0;
+ return false;
+ }
+ return true;
+ }
+
+ void encode_header()
+ {
+ char header[header_length + 1] = "";
+ std::sprintf(header, "%4d", static_cast<int>(body_length_));
+ std::memcpy(data_, header, header_length);
+ }
+
+private:
+ char data_[header_length + max_body_length];
+ std::size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/chat/chat_server.cpp b/3rdparty/asio/src/examples/cpp11/chat/chat_server.cpp
new file mode 100644
index 00000000000..6e5ba3b8ee2
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/chat/chat_server.cpp
@@ -0,0 +1,227 @@
+//
+// chat_server.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <set>
+#include <utility>
+#include "asio.hpp"
+#include "chat_message.hpp"
+
+using asio::ip::tcp;
+
+//----------------------------------------------------------------------
+
+typedef std::deque<chat_message> chat_message_queue;
+
+//----------------------------------------------------------------------
+
+class chat_participant
+{
+public:
+ virtual ~chat_participant() {}
+ virtual void deliver(const chat_message& msg) = 0;
+};
+
+typedef std::shared_ptr<chat_participant> chat_participant_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_room
+{
+public:
+ void join(chat_participant_ptr participant)
+ {
+ participants_.insert(participant);
+ for (auto msg: recent_msgs_)
+ participant->deliver(msg);
+ }
+
+ void leave(chat_participant_ptr participant)
+ {
+ participants_.erase(participant);
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ recent_msgs_.push_back(msg);
+ while (recent_msgs_.size() > max_recent_msgs)
+ recent_msgs_.pop_front();
+
+ for (auto participant: participants_)
+ participant->deliver(msg);
+ }
+
+private:
+ std::set<chat_participant_ptr> participants_;
+ enum { max_recent_msgs = 100 };
+ chat_message_queue recent_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_session
+ : public chat_participant,
+ public std::enable_shared_from_this<chat_session>
+{
+public:
+ chat_session(tcp::socket socket, chat_room& room)
+ : socket_(std::move(socket)),
+ room_(room)
+ {
+ }
+
+ void start()
+ {
+ room_.join(shared_from_this());
+ do_read_header();
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ do_write();
+ }
+ }
+
+private:
+ void do_read_header()
+ {
+ auto self(shared_from_this());
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.data(), chat_message::header_length),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec && read_msg_.decode_header())
+ {
+ do_read_body();
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ void do_read_body()
+ {
+ auto self(shared_from_this());
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ room_.deliver(read_msg_);
+ do_read_header();
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ void do_write()
+ {
+ auto self(shared_from_this());
+ asio::async_write(socket_,
+ asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ do_write();
+ }
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ tcp::socket socket_;
+ chat_room& room_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_server
+{
+public:
+ chat_server(asio::io_context& io_context,
+ const tcp::endpoint& endpoint)
+ : acceptor_(io_context, endpoint)
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<chat_session>(std::move(socket), room_)->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+ chat_room room_;
+};
+
+//----------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc < 2)
+ {
+ std::cerr << "Usage: chat_server <port> [<port> ...]\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ std::list<chat_server> servers;
+ for (int i = 1; i < argc; ++i)
+ {
+ tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i]));
+ servers.emplace_back(io_context, endpoint);
+ }
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/.gitignore b/3rdparty/asio/src/examples/cpp11/echo/.gitignore
new file mode 100644
index 00000000000..0882fa6ced3
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/.gitignore
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+*_server
+*_client
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp b/3rdparty/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp
new file mode 100644
index 00000000000..d76ebe94aae
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp
@@ -0,0 +1,114 @@
+//
+// async_tcp_echo_server.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <utility>
+#include "asio.hpp"
+
+using asio::ip::tcp;
+
+class session
+ : public std::enable_shared_from_this<session>
+{
+public:
+ session(tcp::socket socket)
+ : socket_(std::move(socket))
+ {
+ }
+
+ void start()
+ {
+ do_read();
+ }
+
+private:
+ void do_read()
+ {
+ auto self(shared_from_this());
+ socket_.async_read_some(asio::buffer(data_, max_length),
+ [this, self](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ do_write(length);
+ }
+ });
+ }
+
+ void do_write(std::size_t length)
+ {
+ auto self(shared_from_this());
+ asio::async_write(socket_, asio::buffer(data_, length),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ do_read();
+ }
+ });
+ }
+
+ tcp::socket socket_;
+ enum { max_length = 1024 };
+ char data_[max_length];
+};
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<session>(std::move(socket))->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: async_tcp_echo_server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(argv[1]));
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/async_udp_echo_server.cpp b/3rdparty/asio/src/examples/cpp11/echo/async_udp_echo_server.cpp
new file mode 100644
index 00000000000..8eb1b37f8b6
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/async_udp_echo_server.cpp
@@ -0,0 +1,82 @@
+//
+// async_udp_echo_server.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <iostream>
+#include "asio.hpp"
+
+using asio::ip::udp;
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : socket_(io_context, udp::endpoint(udp::v4(), port))
+ {
+ do_receive();
+ }
+
+ void do_receive()
+ {
+ socket_.async_receive_from(
+ asio::buffer(data_, max_length), sender_endpoint_,
+ [this](std::error_code ec, std::size_t bytes_recvd)
+ {
+ if (!ec && bytes_recvd > 0)
+ {
+ do_send(bytes_recvd);
+ }
+ else
+ {
+ do_receive();
+ }
+ });
+ }
+
+ void do_send(std::size_t length)
+ {
+ socket_.async_send_to(
+ asio::buffer(data_, length), sender_endpoint_,
+ [this](std::error_code /*ec*/, std::size_t /*bytes_sent*/)
+ {
+ do_receive();
+ });
+ }
+
+private:
+ udp::socket socket_;
+ udp::endpoint sender_endpoint_;
+ enum { max_length = 1024 };
+ char data_[max_length];
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: async_udp_echo_server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(argv[1]));
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp b/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp
new file mode 100644
index 00000000000..c7c648df97f
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp
@@ -0,0 +1,55 @@
+//
+// blocking_tcp_echo_client.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include "asio.hpp"
+
+using asio::ip::tcp;
+
+enum { max_length = 1024 };
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ tcp::socket s(io_context);
+ tcp::resolver resolver(io_context);
+ asio::connect(s, resolver.resolve(argv[1], argv[2]));
+
+ std::cout << "Enter message: ";
+ char request[max_length];
+ std::cin.getline(request, max_length);
+ size_t request_length = std::strlen(request);
+ asio::write(s, asio::buffer(request, request_length));
+
+ char reply[max_length];
+ size_t reply_length = asio::read(s,
+ asio::buffer(reply, request_length));
+ std::cout << "Reply is: ";
+ std::cout.write(reply, reply_length);
+ std::cout << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp b/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp
new file mode 100644
index 00000000000..84a72d44453
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp
@@ -0,0 +1,74 @@
+//
+// blocking_tcp_echo_server.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+#include <utility>
+#include "asio.hpp"
+
+using asio::ip::tcp;
+
+const int max_length = 1024;
+
+void session(tcp::socket sock)
+{
+ try
+ {
+ for (;;)
+ {
+ char data[max_length];
+
+ asio::error_code error;
+ size_t length = sock.read_some(asio::buffer(data), error);
+ if (error == asio::error::eof)
+ break; // Connection closed cleanly by peer.
+ else if (error)
+ throw asio::system_error(error); // Some other error.
+
+ asio::write(sock, asio::buffer(data, length));
+ }
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception in thread: " << e.what() << "\n";
+ }
+}
+
+void server(asio::io_context& io_context, unsigned short port)
+{
+ tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), port));
+ for (;;)
+ {
+ std::thread(session, a.accept()).detach();
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: blocking_tcp_echo_server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server(io_context, std::atoi(argv[1]));
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_client.cpp b/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_client.cpp
new file mode 100644
index 00000000000..1d15780c429
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_client.cpp
@@ -0,0 +1,58 @@
+//
+// blocking_udp_echo_client.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include "asio.hpp"
+
+using asio::ip::udp;
+
+enum { max_length = 1024 };
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cerr << "Usage: blocking_udp_echo_client <host> <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ udp::socket s(io_context, udp::endpoint(udp::v4(), 0));
+
+ udp::resolver resolver(io_context);
+ udp::resolver::results_type endpoints =
+ resolver.resolve(udp::v4(), argv[1], argv[2]);
+
+ std::cout << "Enter message: ";
+ char request[max_length];
+ std::cin.getline(request, max_length);
+ size_t request_length = std::strlen(request);
+ s.send_to(asio::buffer(request, request_length), *endpoints.begin());
+
+ char reply[max_length];
+ udp::endpoint sender_endpoint;
+ size_t reply_length = s.receive_from(
+ asio::buffer(reply, max_length), sender_endpoint);
+ std::cout << "Reply is: ";
+ std::cout.write(reply, reply_length);
+ std::cout << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_server.cpp b/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_server.cpp
new file mode 100644
index 00000000000..8bb51735f26
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/echo/blocking_udp_echo_server.cpp
@@ -0,0 +1,52 @@
+//
+// blocking_udp_echo_server.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <iostream>
+#include "asio.hpp"
+
+using asio::ip::udp;
+
+enum { max_length = 1024 };
+
+void server(asio::io_context& io_context, unsigned short port)
+{
+ udp::socket sock(io_context, udp::endpoint(udp::v4(), port));
+ for (;;)
+ {
+ char data[max_length];
+ udp::endpoint sender_endpoint;
+ size_t length = sock.receive_from(
+ asio::buffer(data, max_length), sender_endpoint);
+ sock.send_to(asio::buffer(data, length), sender_endpoint);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: blocking_udp_echo_server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server(io_context, std::atoi(argv[1]));
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/.gitignore b/3rdparty/asio/src/examples/cpp11/executors/.gitignore
new file mode 100644
index 00000000000..183cecf7165
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/.gitignore
@@ -0,0 +1,5 @@
+actor
+bank_account_[0-9]
+fork_join
+pipeline
+priority_scheduler
diff --git a/3rdparty/asio/src/examples/cpp11/executors/actor.cpp b/3rdparty/asio/src/examples/cpp11/executors/actor.cpp
new file mode 100644
index 00000000000..22dbf206a17
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/actor.cpp
@@ -0,0 +1,286 @@
+#include <asio/defer.hpp>
+#include <asio/executor.hpp>
+#include <asio/post.hpp>
+#include <asio/strand.hpp>
+#include <asio/system_executor.hpp>
+#include <condition_variable>
+#include <deque>
+#include <memory>
+#include <mutex>
+#include <typeinfo>
+#include <vector>
+
+using asio::defer;
+using asio::executor;
+using asio::post;
+using asio::strand;
+using asio::system_executor;
+
+//------------------------------------------------------------------------------
+// A tiny actor framework
+// ~~~~~~~~~~~~~~~~~~~~~~
+
+class actor;
+
+// Used to identify the sender and recipient of messages.
+typedef actor* actor_address;
+
+// Base class for all registered message handlers.
+class message_handler_base
+{
+public:
+ virtual ~message_handler_base() {}
+
+ // Used to determine which message handlers receive an incoming message.
+ virtual const std::type_info& message_id() const = 0;
+};
+
+// Base class for a handler for a specific message type.
+template <class Message>
+class message_handler : public message_handler_base
+{
+public:
+ // Handle an incoming message.
+ virtual void handle_message(Message msg, actor_address from) = 0;
+};
+
+// Concrete message handler for a specific message type.
+template <class Actor, class Message>
+class mf_message_handler : public message_handler<Message>
+{
+public:
+ // Construct a message handler to invoke the specified member function.
+ mf_message_handler(void (Actor::* mf)(Message, actor_address), Actor* a)
+ : function_(mf), actor_(a)
+ {
+ }
+
+ // Used to determine which message handlers receive an incoming message.
+ virtual const std::type_info& message_id() const
+ {
+ return typeid(Message);
+ }
+
+ // Handle an incoming message.
+ virtual void handle_message(Message msg, actor_address from)
+ {
+ (actor_->*function_)(std::move(msg), from);
+ }
+
+ // Determine whether the message handler represents the specified function.
+ bool is_function(void (Actor::* mf)(Message, actor_address)) const
+ {
+ return mf == function_;
+ }
+
+private:
+ void (Actor::* function_)(Message, actor_address);
+ Actor* actor_;
+};
+
+// Base class for all actors.
+class actor
+{
+public:
+ virtual ~actor()
+ {
+ }
+
+ // Obtain the actor's address for use as a message sender or recipient.
+ actor_address address()
+ {
+ return this;
+ }
+
+ // Send a message from one actor to another.
+ template <class Message>
+ friend void send(Message msg, actor_address from, actor_address to)
+ {
+ // Execute the message handler in the context of the target's executor.
+ post(to->executor_,
+ [=]
+ {
+ to->call_handler(std::move(msg), from);
+ });
+ }
+
+protected:
+ // Construct the actor to use the specified executor for all message handlers.
+ actor(executor e)
+ : executor_(std::move(e))
+ {
+ }
+
+ // Register a handler for a specific message type. Duplicates are permitted.
+ template <class Actor, class Message>
+ void register_handler(void (Actor::* mf)(Message, actor_address))
+ {
+ handlers_.push_back(
+ std::make_shared<mf_message_handler<Actor, Message>>(
+ mf, static_cast<Actor*>(this)));
+ }
+
+ // Deregister a handler. Removes only the first matching handler.
+ template <class Actor, class Message>
+ void deregister_handler(void (Actor::* mf)(Message, actor_address))
+ {
+ const std::type_info& id = typeid(message_handler<Message>);
+ for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter)
+ {
+ if ((*iter)->message_id() == id)
+ {
+ auto mh = static_cast<mf_message_handler<Actor, Message>*>(iter->get());
+ if (mh->is_function(mf))
+ {
+ handlers_.erase(iter);
+ return;
+ }
+ }
+ }
+ }
+
+ // Send a message from within a message handler.
+ template <class Message>
+ void tail_send(Message msg, actor_address to)
+ {
+ // Execute the message handler in the context of the target's executor.
+ actor* from = this;
+ defer(to->executor_,
+ [=]
+ {
+ to->call_handler(std::move(msg), from);
+ });
+ }
+
+private:
+ // Find the matching message handlers, if any, and call them.
+ template <class Message>
+ void call_handler(Message msg, actor_address from)
+ {
+ const std::type_info& message_id = typeid(Message);
+ for (auto& h: handlers_)
+ {
+ if (h->message_id() == message_id)
+ {
+ auto mh = static_cast<message_handler<Message>*>(h.get());
+ mh->handle_message(msg, from);
+ }
+ }
+ }
+
+ // All messages associated with a single actor object should be processed
+ // non-concurrently. We use a strand to ensure non-concurrent execution even
+ // if the underlying executor may use multiple threads.
+ strand<executor> executor_;
+
+ std::vector<std::shared_ptr<message_handler_base>> handlers_;
+};
+
+// A concrete actor that allows synchronous message retrieval.
+template <class Message>
+class receiver : public actor
+{
+public:
+ receiver()
+ : actor(system_executor())
+ {
+ register_handler(&receiver::message_handler);
+ }
+
+ // Block until a message has been received.
+ Message wait()
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ condition_.wait(lock, [this]{ return !message_queue_.empty(); });
+ Message msg(std::move(message_queue_.front()));
+ message_queue_.pop_front();
+ return msg;
+ }
+
+private:
+ // Handle a new message by adding it to the queue and waking a waiter.
+ void message_handler(Message msg, actor_address /* from */)
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ message_queue_.push_back(std::move(msg));
+ condition_.notify_one();
+ }
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::deque<Message> message_queue_;
+};
+
+//------------------------------------------------------------------------------
+
+#include <asio/thread_pool.hpp>
+#include <iostream>
+
+using asio::thread_pool;
+
+class member : public actor
+{
+public:
+ explicit member(executor e)
+ : actor(std::move(e))
+ {
+ register_handler(&member::init_handler);
+ }
+
+private:
+ void init_handler(actor_address next, actor_address from)
+ {
+ next_ = next;
+ caller_ = from;
+
+ register_handler(&member::token_handler);
+ deregister_handler(&member::init_handler);
+ }
+
+ void token_handler(int token, actor_address /*from*/)
+ {
+ int msg(token);
+ actor_address to(caller_);
+
+ if (token > 0)
+ {
+ msg = token - 1;
+ to = next_;
+ }
+
+ tail_send(msg, to);
+ }
+
+ actor_address next_;
+ actor_address caller_;
+};
+
+int main()
+{
+ const std::size_t num_threads = 16;
+ const int num_hops = 50000000;
+ const std::size_t num_actors = 503;
+ const int token_value = (num_hops + num_actors - 1) / num_actors;
+ const std::size_t actors_per_thread = num_actors / num_threads;
+
+ struct single_thread_pool : thread_pool { single_thread_pool() : thread_pool(1) {} };
+ single_thread_pool pools[num_threads];
+ std::vector<std::shared_ptr<member>> members(num_actors);
+ receiver<int> rcvr;
+
+ // Create the member actors.
+ for (std::size_t i = 0; i < num_actors; ++i)
+ members[i] = std::make_shared<member>(pools[(i / actors_per_thread) % num_threads].get_executor());
+
+ // Initialise the actors by passing each one the address of the next actor in the ring.
+ for (std::size_t i = num_actors, next_i = 0; i > 0; next_i = --i)
+ send(members[next_i]->address(), rcvr.address(), members[i - 1]->address());
+
+ // Send exactly one token to each actor, all with the same initial value, rounding up if required.
+ for (std::size_t i = 0; i < num_actors; ++i)
+ send(token_value, rcvr.address(), members[i]->address());
+
+ // Wait for all signal messages, indicating the tokens have all reached zero.
+ for (std::size_t i = 0; i < num_actors; ++i)
+ rcvr.wait();
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/bank_account_1.cpp b/3rdparty/asio/src/examples/cpp11/executors/bank_account_1.cpp
new file mode 100644
index 00000000000..85f7d9582af
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/bank_account_1.cpp
@@ -0,0 +1,54 @@
+#include <asio/post.hpp>
+#include <asio/thread_pool.hpp>
+#include <iostream>
+
+using asio::post;
+using asio::thread_pool;
+
+// Traditional active object pattern.
+// Member functions do not block.
+
+class bank_account
+{
+ int balance_ = 0;
+ mutable thread_pool pool_{1};
+
+public:
+ void deposit(int amount)
+ {
+ post(pool_, [=]
+ {
+ balance_ += amount;
+ });
+ }
+
+ void withdraw(int amount)
+ {
+ post(pool_, [=]
+ {
+ if (balance_ >= amount)
+ balance_ -= amount;
+ });
+ }
+
+ void print_balance() const
+ {
+ post(pool_, [=]
+ {
+ std::cout << "balance = " << balance_ << "\n";
+ });
+ }
+
+ ~bank_account()
+ {
+ pool_.join();
+ }
+};
+
+int main()
+{
+ bank_account acct;
+ acct.deposit(20);
+ acct.withdraw(10);
+ acct.print_balance();
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/bank_account_2.cpp b/3rdparty/asio/src/examples/cpp11/executors/bank_account_2.cpp
new file mode 100644
index 00000000000..b646cb29518
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/bank_account_2.cpp
@@ -0,0 +1,54 @@
+#include <asio/post.hpp>
+#include <asio/thread_pool.hpp>
+#include <asio/use_future.hpp>
+#include <iostream>
+
+using asio::post;
+using asio::thread_pool;
+using asio::use_future;
+
+// Traditional active object pattern.
+// Member functions block until operation is finished.
+
+class bank_account
+{
+ int balance_ = 0;
+ mutable thread_pool pool_{1};
+
+public:
+ void deposit(int amount)
+ {
+ post(pool_,
+ use_future([=]
+ {
+ balance_ += amount;
+ })).get();
+ }
+
+ void withdraw(int amount)
+ {
+ post(pool_,
+ use_future([=]
+ {
+ if (balance_ >= amount)
+ balance_ -= amount;
+ })).get();
+ }
+
+ int balance() const
+ {
+ return post(pool_,
+ use_future([=]
+ {
+ return balance_;
+ })).get();
+ }
+};
+
+int main()
+{
+ bank_account acct;
+ acct.deposit(20);
+ acct.withdraw(10);
+ std::cout << "balance = " << acct.balance() << "\n";
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/fork_join.cpp b/3rdparty/asio/src/examples/cpp11/executors/fork_join.cpp
new file mode 100644
index 00000000000..69716814823
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/fork_join.cpp
@@ -0,0 +1,327 @@
+#include <asio/dispatch.hpp>
+#include <asio/execution_context.hpp>
+#include <asio/thread_pool.hpp>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+using asio::dispatch;
+using asio::execution_context;
+using asio::thread_pool;
+
+// A fixed-size thread pool used to implement fork/join semantics. Functions
+// are scheduled using a simple FIFO queue. Implementing work stealing, or
+// using a queue based on atomic operations, are left as tasks for the reader.
+class fork_join_pool : public execution_context
+{
+public:
+ // The constructor starts a thread pool with the specified number of threads.
+ // Note that the thread_count is not a fixed limit on the pool's concurrency.
+ // Additional threads may temporarily be added to the pool if they join a
+ // fork_executor.
+ explicit fork_join_pool(
+ std::size_t thread_count = std::thread::hardware_concurrency() * 2)
+ : use_count_(1),
+ threads_(thread_count)
+ {
+ try
+ {
+ // Ask each thread in the pool to dequeue and execute functions until
+ // it is time to shut down, i.e. the use count is zero.
+ for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_)
+ {
+ dispatch(threads_, [&]
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (use_count_ > 0)
+ if (!execute_next(lock))
+ condition_.wait(lock);
+ });
+ }
+ }
+ catch (...)
+ {
+ stop_threads();
+ threads_.join();
+ throw;
+ }
+ }
+
+ // The destructor waits for the pool to finish executing functions.
+ ~fork_join_pool()
+ {
+ stop_threads();
+ threads_.join();
+ }
+
+private:
+ friend class fork_executor;
+
+ // The base for all functions that are queued in the pool.
+ struct function_base
+ {
+ std::shared_ptr<std::size_t> work_count_;
+ void (*execute_)(std::shared_ptr<function_base>& p);
+ };
+
+ // Execute the next function from the queue, if any. Returns true if a
+ // function was executed, and false if the queue was empty.
+ bool execute_next(std::unique_lock<std::mutex>& lock)
+ {
+ if (queue_.empty())
+ return false;
+ auto p(queue_.front());
+ queue_.pop();
+ lock.unlock();
+ execute(lock, p);
+ return true;
+ }
+
+ // Execute a function and decrement the outstanding work.
+ void execute(std::unique_lock<std::mutex>& lock,
+ std::shared_ptr<function_base>& p)
+ {
+ std::shared_ptr<std::size_t> work_count(std::move(p->work_count_));
+ try
+ {
+ p->execute_(p);
+ lock.lock();
+ do_work_finished(work_count);
+ }
+ catch (...)
+ {
+ lock.lock();
+ do_work_finished(work_count);
+ throw;
+ }
+ }
+
+ // Increment outstanding work.
+ void do_work_started(const std::shared_ptr<std::size_t>& work_count) noexcept
+ {
+ if (++(*work_count) == 1)
+ ++use_count_;
+ }
+
+ // Decrement outstanding work. Notify waiting threads if we run out.
+ void do_work_finished(const std::shared_ptr<std::size_t>& work_count) noexcept
+ {
+ if (--(*work_count) == 0)
+ {
+ --use_count_;
+ condition_.notify_all();
+ }
+ }
+
+ // Dispatch a function, executing it immediately if the queue is already
+ // loaded. Otherwise adds the function to the queue and wakes a thread.
+ void do_dispatch(std::shared_ptr<function_base> p,
+ const std::shared_ptr<std::size_t>& work_count)
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (queue_.size() > thread_count_ * 16)
+ {
+ do_work_started(work_count);
+ lock.unlock();
+ execute(lock, p);
+ }
+ else
+ {
+ queue_.push(p);
+ do_work_started(work_count);
+ condition_.notify_one();
+ }
+ }
+
+ // Add a function to the queue and wake a thread.
+ void do_post(std::shared_ptr<function_base> p,
+ const std::shared_ptr<std::size_t>& work_count)
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ queue_.push(p);
+ do_work_started(work_count);
+ condition_.notify_one();
+ }
+
+ // Ask all threads to shut down.
+ void stop_threads()
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ --use_count_;
+ condition_.notify_all();
+ }
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::queue<std::shared_ptr<function_base>> queue_;
+ std::size_t use_count_;
+ std::size_t thread_count_;
+ thread_pool threads_;
+};
+
+// A class that satisfies the Executor requirements. Every function or piece of
+// work associated with a fork_executor is part of a single, joinable group.
+class fork_executor
+{
+public:
+ fork_executor(fork_join_pool& ctx)
+ : context_(ctx),
+ work_count_(std::make_shared<std::size_t>(0))
+ {
+ }
+
+ fork_join_pool& context() const noexcept
+ {
+ return context_;
+ }
+
+ void on_work_started() const noexcept
+ {
+ std::lock_guard<std::mutex> lock(context_.mutex_);
+ context_.do_work_started(work_count_);
+ }
+
+ void on_work_finished() const noexcept
+ {
+ std::lock_guard<std::mutex> lock(context_.mutex_);
+ context_.do_work_finished(work_count_);
+ }
+
+ template <class Func, class Alloc>
+ void dispatch(Func&& f, const Alloc& a) const
+ {
+ auto p(std::allocate_shared<function<Func>>(
+ typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
+ std::move(f), work_count_));
+ context_.do_dispatch(p, work_count_);
+ }
+
+ template <class Func, class Alloc>
+ void post(Func f, const Alloc& a) const
+ {
+ auto p(std::allocate_shared<function<Func>>(
+ typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
+ std::move(f), work_count_));
+ context_.do_post(p, work_count_);
+ }
+
+ template <class Func, class Alloc>
+ void defer(Func&& f, const Alloc& a) const
+ {
+ post(std::forward<Func>(f), a);
+ }
+
+ friend bool operator==(const fork_executor& a,
+ const fork_executor& b) noexcept
+ {
+ return a.work_count_ == b.work_count_;
+ }
+
+ friend bool operator!=(const fork_executor& a,
+ const fork_executor& b) noexcept
+ {
+ return a.work_count_ != b.work_count_;
+ }
+
+ // Block until all work associated with the executor is complete. While it is
+ // waiting, the thread may be borrowed to execute functions from the queue.
+ void join() const
+ {
+ std::unique_lock<std::mutex> lock(context_.mutex_);
+ while (*work_count_ > 0)
+ if (!context_.execute_next(lock))
+ context_.condition_.wait(lock);
+ }
+
+private:
+ template <class Func>
+ struct function : fork_join_pool::function_base
+ {
+ explicit function(Func f, const std::shared_ptr<std::size_t>& w)
+ : function_(std::move(f))
+ {
+ work_count_ = w;
+ execute_ = [](std::shared_ptr<fork_join_pool::function_base>& p)
+ {
+ Func tmp(std::move(static_cast<function*>(p.get())->function_));
+ p.reset();
+ tmp();
+ };
+ }
+
+ Func function_;
+ };
+
+ fork_join_pool& context_;
+ std::shared_ptr<std::size_t> work_count_;
+};
+
+// Helper class to automatically join a fork_executor when exiting a scope.
+class join_guard
+{
+public:
+ explicit join_guard(const fork_executor& ex) : ex_(ex) {}
+ join_guard(const join_guard&) = delete;
+ join_guard(join_guard&&) = delete;
+ ~join_guard() { ex_.join(); }
+
+private:
+ fork_executor ex_;
+};
+
+//------------------------------------------------------------------------------
+
+#include <algorithm>
+#include <iostream>
+#include <random>
+#include <vector>
+
+fork_join_pool pool;
+
+template <class Iterator>
+void fork_join_sort(Iterator begin, Iterator end)
+{
+ std::size_t n = end - begin;
+ if (n > 32768)
+ {
+ {
+ fork_executor fork(pool);
+ join_guard join(fork);
+ dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
+ dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); });
+ }
+ std::inplace_merge(begin, begin + n / 2, end);
+ }
+ else
+ {
+ std::sort(begin, end);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage: fork_join <size>\n";
+ return 1;
+ }
+
+ std::vector<double> vec(std::atoll(argv[1]));
+ std::iota(vec.begin(), vec.end(), 0);
+
+ std::random_device rd;
+ std::mt19937 g(rd());
+ std::shuffle(vec.begin(), vec.end(), g);
+
+ std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+
+ fork_join_sort(vec.begin(), vec.end());
+
+ std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start;
+
+ std::cout << "sort took ";
+ std::cout << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
+ std::cout << " microseconds" << std::endl;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/pipeline.cpp b/3rdparty/asio/src/examples/cpp11/executors/pipeline.cpp
new file mode 100644
index 00000000000..86bf860cb9c
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/pipeline.cpp
@@ -0,0 +1,298 @@
+#include <asio/associated_executor.hpp>
+#include <asio/bind_executor.hpp>
+#include <asio/execution_context.hpp>
+#include <asio/post.hpp>
+#include <asio/system_executor.hpp>
+#include <asio/use_future.hpp>
+#include <condition_variable>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <vector>
+
+using asio::execution_context;
+using asio::executor_binder;
+using asio::get_associated_executor;
+using asio::post;
+using asio::system_executor;
+using asio::use_future;
+using asio::use_service;
+
+// An executor that launches a new thread for each function submitted to it.
+// This class satisfies the Executor requirements.
+class thread_executor
+{
+private:
+ // Service to track all threads started through a thread_executor.
+ class thread_bag : public execution_context::service
+ {
+ public:
+ typedef thread_bag key_type;
+
+ explicit thread_bag(execution_context& ctx)
+ : execution_context::service(ctx)
+ {
+ }
+
+ void add_thread(std::thread&& t)
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ threads_.push_back(std::move(t));
+ }
+
+ private:
+ virtual void shutdown()
+ {
+ for (auto& t : threads_)
+ t.join();
+ }
+
+ std::mutex mutex_;
+ std::vector<std::thread> threads_;
+ };
+
+public:
+ execution_context& context() const noexcept
+ {
+ return system_executor().context();
+ }
+
+ void on_work_started() const noexcept
+ {
+ // This executor doesn't count work.
+ }
+
+ void on_work_finished() const noexcept
+ {
+ // This executor doesn't count work.
+ }
+
+ template <class Func, class Alloc>
+ void dispatch(Func&& f, const Alloc& a) const
+ {
+ post(std::forward<Func>(f), a);
+ }
+
+ template <class Func, class Alloc>
+ void post(Func f, const Alloc&) const
+ {
+ thread_bag& bag = use_service<thread_bag>(context());
+ bag.add_thread(std::thread(std::move(f)));
+ }
+
+ template <class Func, class Alloc>
+ void defer(Func&& f, const Alloc& a) const
+ {
+ post(std::forward<Func>(f), a);
+ }
+
+ friend bool operator==(const thread_executor&,
+ const thread_executor&) noexcept
+ {
+ return true;
+ }
+
+ friend bool operator!=(const thread_executor&,
+ const thread_executor&) noexcept
+ {
+ return false;
+ }
+};
+
+// Base class for all thread-safe queue implementations.
+class queue_impl_base
+{
+ template <class> friend class queue_front;
+ template <class> friend class queue_back;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool stop_ = false;
+};
+
+// Underlying implementation of a thread-safe queue, shared between the
+// queue_front and queue_back classes.
+template <class T>
+class queue_impl : public queue_impl_base
+{
+ template <class> friend class queue_front;
+ template <class> friend class queue_back;
+ std::queue<T> queue_;
+};
+
+// The front end of a queue between consecutive pipeline stages.
+template <class T>
+class queue_front
+{
+public:
+ typedef T value_type;
+
+ explicit queue_front(std::shared_ptr<queue_impl<T>> impl)
+ : impl_(impl)
+ {
+ }
+
+ void push(T t)
+ {
+ std::unique_lock<std::mutex> lock(impl_->mutex_);
+ impl_->queue_.push(std::move(t));
+ impl_->condition_.notify_one();
+ }
+
+ void stop()
+ {
+ std::unique_lock<std::mutex> lock(impl_->mutex_);
+ impl_->stop_ = true;
+ impl_->condition_.notify_one();
+ }
+
+private:
+ std::shared_ptr<queue_impl<T>> impl_;
+};
+
+// The back end of a queue between consecutive pipeline stages.
+template <class T>
+class queue_back
+{
+public:
+ typedef T value_type;
+
+ explicit queue_back(std::shared_ptr<queue_impl<T>> impl)
+ : impl_(impl)
+ {
+ }
+
+ bool pop(T& t)
+ {
+ std::unique_lock<std::mutex> lock(impl_->mutex_);
+ while (impl_->queue_.empty() && !impl_->stop_)
+ impl_->condition_.wait(lock);
+ if (!impl_->queue_.empty())
+ {
+ t = impl_->queue_.front();
+ impl_->queue_.pop();
+ return true;
+ }
+ return false;
+ }
+
+private:
+ std::shared_ptr<queue_impl<T>> impl_;
+};
+
+// Launch the last stage in a pipeline.
+template <class T, class F>
+std::future<void> pipeline(queue_back<T> in, F f)
+{
+ // Get the function's associated executor, defaulting to thread_executor.
+ auto ex = get_associated_executor(f, thread_executor());
+
+ // Run the function, and as we're the last stage return a future so that the
+ // caller can wait for the pipeline to finish.
+ return post(ex, use_future([in, f]() mutable { f(in); }));
+}
+
+// Launch an intermediate stage in a pipeline.
+template <class T, class F, class... Tail>
+std::future<void> pipeline(queue_back<T> in, F f, Tail... t)
+{
+ // Determine the output queue type.
+ typedef typename executor_binder<F, thread_executor>::second_argument_type::value_type output_value_type;
+
+ // Create the output queue and its implementation.
+ auto out_impl = std::make_shared<queue_impl<output_value_type>>();
+ queue_front<output_value_type> out(out_impl);
+ queue_back<output_value_type> next_in(out_impl);
+
+ // Get the function's associated executor, defaulting to thread_executor.
+ auto ex = get_associated_executor(f, thread_executor());
+
+ // Run the function.
+ post(ex, [in, out, f]() mutable
+ {
+ f(in, out);
+ out.stop();
+ });
+
+ // Launch the rest of the pipeline.
+ return pipeline(next_in, std::move(t)...);
+}
+
+// Launch the first stage in a pipeline.
+template <class F, class... Tail>
+std::future<void> pipeline(F f, Tail... t)
+{
+ // Determine the output queue type.
+ typedef typename executor_binder<F, thread_executor>::argument_type::value_type output_value_type;
+
+ // Create the output queue and its implementation.
+ auto out_impl = std::make_shared<queue_impl<output_value_type>>();
+ queue_front<output_value_type> out(out_impl);
+ queue_back<output_value_type> next_in(out_impl);
+
+ // Get the function's associated executor, defaulting to thread_executor.
+ auto ex = get_associated_executor(f, thread_executor());
+
+ // Run the function.
+ post(ex, [out, f]() mutable
+ {
+ f(out);
+ out.stop();
+ });
+
+ // Launch the rest of the pipeline.
+ return pipeline(next_in, std::move(t)...);
+}
+
+//------------------------------------------------------------------------------
+
+#include <asio/thread_pool.hpp>
+#include <iostream>
+#include <string>
+
+using asio::bind_executor;
+using asio::thread_pool;
+
+void reader(queue_front<std::string> out)
+{
+ std::string line;
+ while (std::getline(std::cin, line))
+ out.push(line);
+}
+
+void filter(queue_back<std::string> in, queue_front<std::string> out)
+{
+ std::string line;
+ while (in.pop(line))
+ if (line.length() > 5)
+ out.push(line);
+}
+
+void upper(queue_back<std::string> in, queue_front<std::string> out)
+{
+ std::string line;
+ while (in.pop(line))
+ {
+ std::string new_line;
+ for (char c : line)
+ new_line.push_back(std::toupper(c));
+ out.push(new_line);
+ }
+}
+
+void writer(queue_back<std::string> in)
+{
+ std::size_t count = 0;
+ std::string line;
+ while (in.pop(line))
+ std::cout << count++ << ": " << line << std::endl;
+}
+
+int main()
+{
+ thread_pool pool;
+
+ auto f = pipeline(reader, filter, bind_executor(pool, upper), writer);
+ f.wait();
+}
diff --git a/3rdparty/asio/src/examples/cpp11/executors/priority_scheduler.cpp b/3rdparty/asio/src/examples/cpp11/executors/priority_scheduler.cpp
new file mode 100644
index 00000000000..fb38fa2ce4b
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/executors/priority_scheduler.cpp
@@ -0,0 +1,168 @@
+#include <asio/dispatch.hpp>
+#include <asio/execution_context.hpp>
+#include <condition_variable>
+#include <iostream>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+using asio::dispatch;
+using asio::execution_context;
+
+class priority_scheduler : public execution_context
+{
+public:
+ // A class that satisfies the Executor requirements.
+ class executor_type
+ {
+ public:
+ executor_type(priority_scheduler& ctx, int pri) noexcept
+ : context_(ctx), priority_(pri)
+ {
+ }
+
+ priority_scheduler& context() const noexcept
+ {
+ return context_;
+ }
+
+ void on_work_started() const noexcept
+ {
+ // This executor doesn't count work. Instead, the scheduler simply runs
+ // until explicitly stopped.
+ }
+
+ void on_work_finished() const noexcept
+ {
+ // This executor doesn't count work. Instead, the scheduler simply runs
+ // until explicitly stopped.
+ }
+
+ template <class Func, class Alloc>
+ void dispatch(Func&& f, const Alloc& a) const
+ {
+ post(std::forward<Func>(f), a);
+ }
+
+ template <class Func, class Alloc>
+ void post(Func f, const Alloc& a) const
+ {
+ auto p(std::allocate_shared<item<Func>>(
+ typename std::allocator_traits<
+ Alloc>::template rebind_alloc<char>(a),
+ priority_, std::move(f)));
+ std::lock_guard<std::mutex> lock(context_.mutex_);
+ context_.queue_.push(p);
+ context_.condition_.notify_one();
+ }
+
+ template <class Func, class Alloc>
+ void defer(Func&& f, const Alloc& a) const
+ {
+ post(std::forward<Func>(f), a);
+ }
+
+ friend bool operator==(const executor_type& a,
+ const executor_type& b) noexcept
+ {
+ return &a.context_ == &b.context_;
+ }
+
+ friend bool operator!=(const executor_type& a,
+ const executor_type& b) noexcept
+ {
+ return &a.context_ != &b.context_;
+ }
+
+ private:
+ priority_scheduler& context_;
+ int priority_;
+ };
+
+ executor_type get_executor(int pri = 0) noexcept
+ {
+ return executor_type(*const_cast<priority_scheduler*>(this), pri);
+ }
+
+ void run()
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ for (;;)
+ {
+ condition_.wait(lock, [&]{ return stopped_ || !queue_.empty(); });
+ if (stopped_)
+ return;
+ auto p(queue_.top());
+ queue_.pop();
+ lock.unlock();
+ p->execute_(p);
+ lock.lock();
+ }
+ }
+
+ void stop()
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ stopped_ = true;
+ condition_.notify_all();
+ }
+
+private:
+ struct item_base
+ {
+ int priority_;
+ void (*execute_)(std::shared_ptr<item_base>&);
+ };
+
+ template <class Func>
+ struct item : item_base
+ {
+ item(int pri, Func f) : function_(std::move(f))
+ {
+ priority_ = pri;
+ execute_ = [](std::shared_ptr<item_base>& p)
+ {
+ Func tmp(std::move(static_cast<item*>(p.get())->function_));
+ p.reset();
+ tmp();
+ };
+ }
+
+ Func function_;
+ };
+
+ struct item_comp
+ {
+ bool operator()(
+ const std::shared_ptr<item_base>& a,
+ const std::shared_ptr<item_base>& b)
+ {
+ return a->priority_ < b->priority_;
+ }
+ };
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::priority_queue<
+ std::shared_ptr<item_base>,
+ std::vector<std::shared_ptr<item_base>>,
+ item_comp> queue_;
+ bool stopped_ = false;
+};
+
+int main()
+{
+ priority_scheduler sched;
+ auto low = sched.get_executor(0);
+ auto med = sched.get_executor(1);
+ auto high = sched.get_executor(2);
+ dispatch(low, []{ std::cout << "1\n"; });
+ dispatch(low, []{ std::cout << "11\n"; });
+ dispatch(med, []{ std::cout << "2\n"; });
+ dispatch(med, []{ std::cout << "22\n"; });
+ dispatch(high, []{ std::cout << "3\n"; });
+ dispatch(high, []{ std::cout << "33\n"; });
+ dispatch(high, []{ std::cout << "333\n"; });
+ dispatch(sched.get_executor(-1), [&]{ sched.stop(); });
+ sched.run();
+}
diff --git a/3rdparty/asio/src/examples/cpp11/futures/.gitignore b/3rdparty/asio/src/examples/cpp11/futures/.gitignore
new file mode 100644
index 00000000000..0882fa6ced3
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/futures/.gitignore
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+*_server
+*_client
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/futures/daytime_client.cpp b/3rdparty/asio/src/examples/cpp11/futures/daytime_client.cpp
new file mode 100644
index 00000000000..0004e124ff6
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/futures/daytime_client.cpp
@@ -0,0 +1,94 @@
+//
+// daytime_client.cpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <array>
+#include <future>
+#include <iostream>
+#include <thread>
+#include <asio/io_context.hpp>
+#include <asio/ip/udp.hpp>
+#include <asio/use_future.hpp>
+
+using asio::ip::udp;
+
+void get_daytime(asio::io_context& io_context, const char* hostname)
+{
+ try
+ {
+ udp::resolver resolver(io_context);
+
+ std::future<udp::resolver::results_type> endpoints =
+ resolver.async_resolve(
+ udp::v4(), hostname, "daytime",
+ asio::use_future);
+
+ // The async_resolve operation above returns the endpoints as a future
+ // value that is not retrieved ...
+
+ udp::socket socket(io_context, udp::v4());
+
+ std::array<char, 1> send_buf = {{ 0 }};
+ std::future<std::size_t> send_length =
+ socket.async_send_to(asio::buffer(send_buf),
+ *endpoints.get().begin(), // ... until here. This call may block.
+ asio::use_future);
+
+ // Do other things here while the send completes.
+
+ send_length.get(); // Blocks until the send is complete. Throws any errors.
+
+ std::array<char, 128> recv_buf;
+ udp::endpoint sender_endpoint;
+ std::future<std::size_t> recv_length =
+ socket.async_receive_from(
+ asio::buffer(recv_buf),
+ sender_endpoint,
+ asio::use_future);
+
+ // Do other things here while the receive completes.
+
+ std::cout.write(
+ recv_buf.data(),
+ recv_length.get()); // Blocks until receive is complete.
+ }
+ catch (std::system_error& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: daytime_client <host>" << std::endl;
+ return 1;
+ }
+
+ // We run the io_context off in its own thread so that it operates
+ // completely asynchronously with respect to the rest of the program.
+ asio::io_context io_context;
+ auto work = asio::make_work_guard(io_context);
+ std::thread thread([&io_context](){ io_context.run(); });
+
+ get_daytime(io_context, argv[1]);
+
+ io_context.stop();
+ thread.join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp b/3rdparty/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp
new file mode 100644
index 00000000000..41b355c748c
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp
@@ -0,0 +1,201 @@
+//
+// custom_tracking.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CUSTOM_TRACKING_HPP
+#define CUSTOM_TRACKING_HPP
+
+#include <cinttypes>
+#include <cstdint>
+#include <cstdio>
+
+# define ASIO_INHERIT_TRACKED_HANDLER \
+ : public ::custom_tracking::tracked_handler
+
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \
+ , public ::custom_tracking::tracked_handler
+
+# define ASIO_HANDLER_TRACKING_INIT \
+ ::custom_tracking::init()
+
+# define ASIO_HANDLER_CREATION(args) \
+ ::custom_tracking::creation args
+
+# define ASIO_HANDLER_COMPLETION(args) \
+ ::custom_tracking::completion tracked_completion args
+
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) \
+ tracked_completion.invocation_begin args
+
+# define ASIO_HANDLER_INVOCATION_END \
+ tracked_completion.invocation_end()
+
+# define ASIO_HANDLER_OPERATION(args) \
+ ::custom_tracking::operation args
+
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \
+ ::custom_tracking::reactor_registration args
+
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \
+ ::custom_tracking::reactor_deregistration args
+
+# define ASIO_HANDLER_REACTOR_READ_EVENT 1
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4
+
+# define ASIO_HANDLER_REACTOR_EVENTS(args) \
+ ::custom_tracking::reactor_events args
+
+# define ASIO_HANDLER_REACTOR_OPERATION(args) \
+ ::custom_tracking::reactor_operation args
+
+struct custom_tracking
+{
+ // Base class for objects containing tracked handlers.
+ struct tracked_handler
+ {
+ std::uintmax_t handler_id_ = 0; // To uniquely identify a handler.
+ std::uintmax_t tree_id_ = 0; // To identify related handlers.
+ const char* object_type_; // The object type associated with the handler.
+ std::uintmax_t native_handle_; // Native handle, if any.
+ };
+
+ // Initialise the tracking system.
+ static void init()
+ {
+ }
+
+ // Record the creation of a tracked handler.
+ static void creation(asio::execution_context& /*ctx*/, tracked_handler& h,
+ const char* object_type, void* /*object*/,
+ std::uintmax_t native_handle, const char* op_name)
+ {
+ // Generate a unique id for the new handler.
+ static std::atomic<std::uintmax_t> next_handler_id{1};
+ h.handler_id_ = next_handler_id++;
+
+ // Copy the tree identifier forward from the current handler.
+ if (*current_completion())
+ h.tree_id_ = (*current_completion())->handler_.tree_id_;
+
+ // Store various attributes of the operation to use in later output.
+ h.object_type_ = object_type;
+ h.native_handle_ = native_handle;
+
+ std::printf(
+ "Starting operation %s.%s for native_handle = %" PRIuMAX
+ ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n",
+ object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_);
+ }
+
+ struct completion
+ {
+ explicit completion(const tracked_handler& h)
+ : handler_(h),
+ next_(*current_completion())
+ {
+ *current_completion() = this;
+ }
+
+ completion(const completion&) = delete;
+ completion& operator=(const completion&) = delete;
+
+ // Destructor records only when an exception is thrown from the handler, or
+ // if the memory is being freed without the handler having been invoked.
+ ~completion()
+ {
+ *current_completion() = next_;
+ }
+
+ // Records that handler is to be invoked with the specified arguments.
+ template <class... Args>
+ void invocation_begin(Args&&... /*args*/)
+ {
+ std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n",
+ handler_.handler_id_, handler_.tree_id_);
+ }
+
+ // Record that handler invocation has ended.
+ void invocation_end()
+ {
+ std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n",
+ handler_.handler_id_, handler_.tree_id_);
+ }
+
+ tracked_handler handler_;
+
+ // Completions may nest. Here we stash a pointer to the outer completion.
+ completion* next_;
+ };
+
+ static completion** current_completion()
+ {
+ static ASIO_THREAD_KEYWORD completion* current = nullptr;
+ return &current;
+ }
+
+ // Record an operation that is not directly associated with a handler.
+ static void operation(asio::execution_context& /*ctx*/,
+ const char* /*object_type*/, void* /*object*/,
+ std::uintmax_t /*native_handle*/, const char* /*op_name*/)
+ {
+ }
+
+ // Record that a descriptor has been registered with the reactor.
+ static void reactor_registration(asio::execution_context& context,
+ uintmax_t native_handle, uintmax_t registration)
+ {
+ std::printf("Adding to reactor native_handle = %" PRIuMAX
+ ", registration = %" PRIuMAX "\n", native_handle, registration);
+ }
+
+ // Record that a descriptor has been deregistered from the reactor.
+ static void reactor_deregistration(asio::execution_context& context,
+ uintmax_t native_handle, uintmax_t registration)
+ {
+ std::printf("Removing from reactor native_handle = %" PRIuMAX
+ ", registration = %" PRIuMAX "\n", native_handle, registration);
+ }
+
+ // Record reactor-based readiness events associated with a descriptor.
+ static void reactor_events(asio::execution_context& context,
+ uintmax_t registration, unsigned events)
+ {
+ std::printf(
+ "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n",
+ registration,
+ (events & ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "",
+ (events & ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "",
+ (events & ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : "");
+ }
+
+ // Record a reactor-based operation that is associated with a handler.
+ static void reactor_operation(const tracked_handler& h,
+ const char* op_name, const asio::error_code& ec)
+ {
+ std::printf(
+ "Performed operation %s.%s for native_handle = %" PRIuMAX
+ ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_,
+ ec.category().name(), ec.value());
+ }
+
+ // Record a reactor-based operation that is associated with a handler.
+ static void reactor_operation(const tracked_handler& h,
+ const char* op_name, const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ std::printf(
+ "Performed operation %s.%s for native_handle = %" PRIuMAX
+ ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name,
+ h.native_handle_, ec.category().name(), ec.value(),
+ static_cast<uintmax_t>(bytes_transferred));
+ }
+};
+
+#endif // CUSTOM_TRACKING_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/.gitignore b/3rdparty/asio/src/examples/cpp11/http/server/.gitignore
new file mode 100644
index 00000000000..0882fa6ced3
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/.gitignore
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+*_server
+*_client
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/connection.cpp b/3rdparty/asio/src/examples/cpp11/http/server/connection.cpp
new file mode 100644
index 00000000000..f4d9cac46e5
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/connection.cpp
@@ -0,0 +1,94 @@
+//
+// connection.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "connection.hpp"
+#include <utility>
+#include <vector>
+#include "connection_manager.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server {
+
+connection::connection(asio::ip::tcp::socket socket,
+ connection_manager& manager, request_handler& handler)
+ : socket_(std::move(socket)),
+ connection_manager_(manager),
+ request_handler_(handler)
+{
+}
+
+void connection::start()
+{
+ do_read();
+}
+
+void connection::stop()
+{
+ socket_.close();
+}
+
+void connection::do_read()
+{
+ auto self(shared_from_this());
+ socket_.async_read_some(asio::buffer(buffer_),
+ [this, self](std::error_code ec, std::size_t bytes_transferred)
+ {
+ if (!ec)
+ {
+ request_parser::result_type result;
+ std::tie(result, std::ignore) = request_parser_.parse(
+ request_, buffer_.data(), buffer_.data() + bytes_transferred);
+
+ if (result == request_parser::good)
+ {
+ request_handler_.handle_request(request_, reply_);
+ do_write();
+ }
+ else if (result == request_parser::bad)
+ {
+ reply_ = reply::stock_reply(reply::bad_request);
+ do_write();
+ }
+ else
+ {
+ do_read();
+ }
+ }
+ else if (ec != asio::error::operation_aborted)
+ {
+ connection_manager_.stop(shared_from_this());
+ }
+ });
+}
+
+void connection::do_write()
+{
+ auto self(shared_from_this());
+ asio::async_write(socket_, reply_.to_buffers(),
+ [this, self](std::error_code ec, std::size_t)
+ {
+ if (!ec)
+ {
+ // Initiate graceful connection closure.
+ asio::error_code ignored_ec;
+ socket_.shutdown(asio::ip::tcp::socket::shutdown_both,
+ ignored_ec);
+ }
+
+ if (ec != asio::error::operation_aborted)
+ {
+ connection_manager_.stop(shared_from_this());
+ }
+ });
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/connection.hpp b/3rdparty/asio/src/examples/cpp11/http/server/connection.hpp
new file mode 100644
index 00000000000..96364db0daa
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/connection.hpp
@@ -0,0 +1,79 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_CONNECTION_HPP
+#define HTTP_CONNECTION_HPP
+
+#include <array>
+#include <memory>
+#include <asio.hpp>
+#include "reply.hpp"
+#include "request.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
+
+namespace http {
+namespace server {
+
+class connection_manager;
+
+/// Represents a single connection from a client.
+class connection
+ : public std::enable_shared_from_this<connection>
+{
+public:
+ connection(const connection&) = delete;
+ connection& operator=(const connection&) = delete;
+
+ /// Construct a connection with the given socket.
+ explicit connection(asio::ip::tcp::socket socket,
+ connection_manager& manager, request_handler& handler);
+
+ /// Start the first asynchronous operation for the connection.
+ void start();
+
+ /// Stop all asynchronous operations associated with the connection.
+ void stop();
+
+private:
+ /// Perform an asynchronous read operation.
+ void do_read();
+
+ /// Perform an asynchronous write operation.
+ void do_write();
+
+ /// Socket for the connection.
+ asio::ip::tcp::socket socket_;
+
+ /// The manager for this connection.
+ connection_manager& connection_manager_;
+
+ /// The handler used to process the incoming request.
+ request_handler& request_handler_;
+
+ /// Buffer for incoming data.
+ std::array<char, 8192> buffer_;
+
+ /// The incoming request.
+ request request_;
+
+ /// The parser for the incoming request.
+ request_parser request_parser_;
+
+ /// The reply to be sent back to the client.
+ reply reply_;
+};
+
+typedef std::shared_ptr<connection> connection_ptr;
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.cpp b/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.cpp
new file mode 100644
index 00000000000..55bfb9ad719
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.cpp
@@ -0,0 +1,40 @@
+//
+// connection_manager.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "connection_manager.hpp"
+
+namespace http {
+namespace server {
+
+connection_manager::connection_manager()
+{
+}
+
+void connection_manager::start(connection_ptr c)
+{
+ connections_.insert(c);
+ c->start();
+}
+
+void connection_manager::stop(connection_ptr c)
+{
+ connections_.erase(c);
+ c->stop();
+}
+
+void connection_manager::stop_all()
+{
+ for (auto c: connections_)
+ c->stop();
+ connections_.clear();
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.hpp b/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.hpp
new file mode 100644
index 00000000000..8dadf416347
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/connection_manager.hpp
@@ -0,0 +1,48 @@
+//
+// connection_manager.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_CONNECTION_MANAGER_HPP
+#define HTTP_CONNECTION_MANAGER_HPP
+
+#include <set>
+#include "connection.hpp"
+
+namespace http {
+namespace server {
+
+/// Manages open connections so that they may be cleanly stopped when the server
+/// needs to shut down.
+class connection_manager
+{
+public:
+ connection_manager(const connection_manager&) = delete;
+ connection_manager& operator=(const connection_manager&) = delete;
+
+ /// Construct a connection manager.
+ connection_manager();
+
+ /// Add the specified connection to the manager and start it.
+ void start(connection_ptr c);
+
+ /// Stop the specified connection.
+ void stop(connection_ptr c);
+
+ /// Stop all connections.
+ void stop_all();
+
+private:
+ /// The managed connections.
+ std::set<connection_ptr> connections_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_MANAGER_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/header.hpp b/3rdparty/asio/src/examples/cpp11/http/server/header.hpp
new file mode 100644
index 00000000000..22e3c4a7a10
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_HEADER_HPP
+#define HTTP_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+
+struct header
+{
+ std::string name;
+ std::string value;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_HEADER_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/main.cpp b/3rdparty/asio/src/examples/cpp11/http/server/main.cpp
new file mode 100644
index 00000000000..44fc930f494
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/main.cpp
@@ -0,0 +1,43 @@
+//
+// main.cpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <iostream>
+#include <string>
+#include <asio.hpp>
+#include "server.hpp"
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr << "Usage: http_server <address> <port> <doc_root>\n";
+ std::cerr << " For IPv4, try:\n";
+ std::cerr << " receiver 0.0.0.0 80 .\n";
+ std::cerr << " For IPv6, try:\n";
+ std::cerr << " receiver 0::0 80 .\n";
+ return 1;
+ }
+
+ // Initialise the server.
+ http::server::server s(argv[1], argv[2], argv[3]);
+
+ // Run the server until stopped.
+ s.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/mime_types.cpp b/3rdparty/asio/src/examples/cpp11/http/server/mime_types.cpp
new file mode 100644
index 00000000000..eb779197189
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/mime_types.cpp
@@ -0,0 +1,45 @@
+//
+// mime_types.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "mime_types.hpp"
+
+namespace http {
+namespace server {
+namespace mime_types {
+
+struct mapping
+{
+ const char* extension;
+ const char* mime_type;
+} mappings[] =
+{
+ { "gif", "image/gif" },
+ { "htm", "text/html" },
+ { "html", "text/html" },
+ { "jpg", "image/jpeg" },
+ { "png", "image/png" }
+};
+
+std::string extension_to_type(const std::string& extension)
+{
+ for (mapping m: mappings)
+ {
+ if (m.extension == extension)
+ {
+ return m.mime_type;
+ }
+ }
+
+ return "text/plain";
+}
+
+} // namespace mime_types
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/mime_types.hpp b/3rdparty/asio/src/examples/cpp11/http/server/mime_types.hpp
new file mode 100644
index 00000000000..2fc0332791f
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_MIME_TYPES_HPP
+#define HTTP_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server
+} // namespace http
+
+#endif // HTTP_MIME_TYPES_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/reply.cpp b/3rdparty/asio/src/examples/cpp11/http/server/reply.cpp
new file mode 100644
index 00000000000..2c9901312bb
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/reply.cpp
@@ -0,0 +1,255 @@
+//
+// reply.cpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "reply.hpp"
+#include <string>
+
+namespace http {
+namespace server {
+
+namespace status_strings {
+
+const std::string ok =
+ "HTTP/1.0 200 OK\r\n";
+const std::string created =
+ "HTTP/1.0 201 Created\r\n";
+const std::string accepted =
+ "HTTP/1.0 202 Accepted\r\n";
+const std::string no_content =
+ "HTTP/1.0 204 No Content\r\n";
+const std::string multiple_choices =
+ "HTTP/1.0 300 Multiple Choices\r\n";
+const std::string moved_permanently =
+ "HTTP/1.0 301 Moved Permanently\r\n";
+const std::string moved_temporarily =
+ "HTTP/1.0 302 Moved Temporarily\r\n";
+const std::string not_modified =
+ "HTTP/1.0 304 Not Modified\r\n";
+const std::string bad_request =
+ "HTTP/1.0 400 Bad Request\r\n";
+const std::string unauthorized =
+ "HTTP/1.0 401 Unauthorized\r\n";
+const std::string forbidden =
+ "HTTP/1.0 403 Forbidden\r\n";
+const std::string not_found =
+ "HTTP/1.0 404 Not Found\r\n";
+const std::string internal_server_error =
+ "HTTP/1.0 500 Internal Server Error\r\n";
+const std::string not_implemented =
+ "HTTP/1.0 501 Not Implemented\r\n";
+const std::string bad_gateway =
+ "HTTP/1.0 502 Bad Gateway\r\n";
+const std::string service_unavailable =
+ "HTTP/1.0 503 Service Unavailable\r\n";
+
+asio::const_buffer to_buffer(reply::status_type status)
+{
+ switch (status)
+ {
+ case reply::ok:
+ return asio::buffer(ok);
+ case reply::created:
+ return asio::buffer(created);
+ case reply::accepted:
+ return asio::buffer(accepted);
+ case reply::no_content:
+ return asio::buffer(no_content);
+ case reply::multiple_choices:
+ return asio::buffer(multiple_choices);
+ case reply::moved_permanently:
+ return asio::buffer(moved_permanently);
+ case reply::moved_temporarily:
+ return asio::buffer(moved_temporarily);
+ case reply::not_modified:
+ return asio::buffer(not_modified);
+ case reply::bad_request:
+ return asio::buffer(bad_request);
+ case reply::unauthorized:
+ return asio::buffer(unauthorized);
+ case reply::forbidden:
+ return asio::buffer(forbidden);
+ case reply::not_found:
+ return asio::buffer(not_found);
+ case reply::internal_server_error:
+ return asio::buffer(internal_server_error);
+ case reply::not_implemented:
+ return asio::buffer(not_implemented);
+ case reply::bad_gateway:
+ return asio::buffer(bad_gateway);
+ case reply::service_unavailable:
+ return asio::buffer(service_unavailable);
+ default:
+ return asio::buffer(internal_server_error);
+ }
+}
+
+} // namespace status_strings
+
+namespace misc_strings {
+
+const char name_value_separator[] = { ':', ' ' };
+const char crlf[] = { '\r', '\n' };
+
+} // namespace misc_strings
+
+std::vector<asio::const_buffer> reply::to_buffers()
+{
+ std::vector<asio::const_buffer> buffers;
+ buffers.push_back(status_strings::to_buffer(status));
+ for (std::size_t i = 0; i < headers.size(); ++i)
+ {
+ header& h = headers[i];
+ buffers.push_back(asio::buffer(h.name));
+ buffers.push_back(asio::buffer(misc_strings::name_value_separator));
+ buffers.push_back(asio::buffer(h.value));
+ buffers.push_back(asio::buffer(misc_strings::crlf));
+ }
+ buffers.push_back(asio::buffer(misc_strings::crlf));
+ buffers.push_back(asio::buffer(content));
+ return buffers;
+}
+
+namespace stock_replies {
+
+const char ok[] = "";
+const char created[] =
+ "<html>"
+ "<head><title>Created</title></head>"
+ "<body><h1>201 Created</h1></body>"
+ "</html>";
+const char accepted[] =
+ "<html>"
+ "<head><title>Accepted</title></head>"
+ "<body><h1>202 Accepted</h1></body>"
+ "</html>";
+const char no_content[] =
+ "<html>"
+ "<head><title>No Content</title></head>"
+ "<body><h1>204 Content</h1></body>"
+ "</html>";
+const char multiple_choices[] =
+ "<html>"
+ "<head><title>Multiple Choices</title></head>"
+ "<body><h1>300 Multiple Choices</h1></body>"
+ "</html>";
+const char moved_permanently[] =
+ "<html>"
+ "<head><title>Moved Permanently</title></head>"
+ "<body><h1>301 Moved Permanently</h1></body>"
+ "</html>";
+const char moved_temporarily[] =
+ "<html>"
+ "<head><title>Moved Temporarily</title></head>"
+ "<body><h1>302 Moved Temporarily</h1></body>"
+ "</html>";
+const char not_modified[] =
+ "<html>"
+ "<head><title>Not Modified</title></head>"
+ "<body><h1>304 Not Modified</h1></body>"
+ "</html>";
+const char bad_request[] =
+ "<html>"
+ "<head><title>Bad Request</title></head>"
+ "<body><h1>400 Bad Request</h1></body>"
+ "</html>";
+const char unauthorized[] =
+ "<html>"
+ "<head><title>Unauthorized</title></head>"
+ "<body><h1>401 Unauthorized</h1></body>"
+ "</html>";
+const char forbidden[] =
+ "<html>"
+ "<head><title>Forbidden</title></head>"
+ "<body><h1>403 Forbidden</h1></body>"
+ "</html>";
+const char not_found[] =
+ "<html>"
+ "<head><title>Not Found</title></head>"
+ "<body><h1>404 Not Found</h1></body>"
+ "</html>";
+const char internal_server_error[] =
+ "<html>"
+ "<head><title>Internal Server Error</title></head>"
+ "<body><h1>500 Internal Server Error</h1></body>"
+ "</html>";
+const char not_implemented[] =
+ "<html>"
+ "<head><title>Not Implemented</title></head>"
+ "<body><h1>501 Not Implemented</h1></body>"
+ "</html>";
+const char bad_gateway[] =
+ "<html>"
+ "<head><title>Bad Gateway</title></head>"
+ "<body><h1>502 Bad Gateway</h1></body>"
+ "</html>";
+const char service_unavailable[] =
+ "<html>"
+ "<head><title>Service Unavailable</title></head>"
+ "<body><h1>503 Service Unavailable</h1></body>"
+ "</html>";
+
+std::string to_string(reply::status_type status)
+{
+ switch (status)
+ {
+ case reply::ok:
+ return ok;
+ case reply::created:
+ return created;
+ case reply::accepted:
+ return accepted;
+ case reply::no_content:
+ return no_content;
+ case reply::multiple_choices:
+ return multiple_choices;
+ case reply::moved_permanently:
+ return moved_permanently;
+ case reply::moved_temporarily:
+ return moved_temporarily;
+ case reply::not_modified:
+ return not_modified;
+ case reply::bad_request:
+ return bad_request;
+ case reply::unauthorized:
+ return unauthorized;
+ case reply::forbidden:
+ return forbidden;
+ case reply::not_found:
+ return not_found;
+ case reply::internal_server_error:
+ return internal_server_error;
+ case reply::not_implemented:
+ return not_implemented;
+ case reply::bad_gateway:
+ return bad_gateway;
+ case reply::service_unavailable:
+ return service_unavailable;
+ default:
+ return internal_server_error;
+ }
+}
+
+} // namespace stock_replies
+
+reply reply::stock_reply(reply::status_type status)
+{
+ reply rep;
+ rep.status = status;
+ rep.content = stock_replies::to_string(status);
+ rep.headers.resize(2);
+ rep.headers[0].name = "Content-Length";
+ rep.headers[0].value = std::to_string(rep.content.size());
+ rep.headers[1].name = "Content-Type";
+ rep.headers[1].value = "text/html";
+ return rep;
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/reply.hpp b/3rdparty/asio/src/examples/cpp11/http/server/reply.hpp
new file mode 100644
index 00000000000..5189ac4363e
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_REPLY_HPP
+#define HTTP_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A reply to be sent to a client.
+struct reply
+{
+ /// The status of the reply.
+ enum status_type
+ {
+ ok = 200,
+ created = 201,
+ accepted = 202,
+ no_content = 204,
+ multiple_choices = 300,
+ moved_permanently = 301,
+ moved_temporarily = 302,
+ not_modified = 304,
+ bad_request = 400,
+ unauthorized = 401,
+ forbidden = 403,
+ not_found = 404,
+ internal_server_error = 500,
+ not_implemented = 501,
+ bad_gateway = 502,
+ service_unavailable = 503
+ } status;
+
+ /// The headers to be included in the reply.
+ std::vector<header> headers;
+
+ /// The content to be sent in the reply.
+ std::string content;
+
+ /// Convert the reply into a vector of buffers. The buffers do not own the
+ /// underlying memory blocks, therefore the reply object must remain valid and
+ /// not be changed until the write operation has completed.
+ std::vector<asio::const_buffer> to_buffers();
+
+ /// Get a stock reply.
+ static reply stock_reply(status_type status);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REPLY_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/request.hpp b/3rdparty/asio/src/examples/cpp11/http/server/request.hpp
new file mode 100644
index 00000000000..129a3990b3d
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/request.hpp
@@ -0,0 +1,34 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_REQUEST_HPP
+#define HTTP_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A request received from a client.
+struct request
+{
+ std::string method;
+ std::string uri;
+ int http_version_major;
+ int http_version_minor;
+ std::vector<header> headers;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/request_handler.cpp b/3rdparty/asio/src/examples/cpp11/http/server/request_handler.cpp
new file mode 100644
index 00000000000..c346ab9791e
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/request_handler.cpp
@@ -0,0 +1,121 @@
+//
+// request_handler.cpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "request_handler.hpp"
+#include <fstream>
+#include <sstream>
+#include <string>
+#include "mime_types.hpp"
+#include "reply.hpp"
+#include "request.hpp"
+
+namespace http {
+namespace server {
+
+request_handler::request_handler(const std::string& doc_root)
+ : doc_root_(doc_root)
+{
+}
+
+void request_handler::handle_request(const request& req, reply& rep)
+{
+ // Decode url to path.
+ std::string request_path;
+ if (!url_decode(req.uri, request_path))
+ {
+ rep = reply::stock_reply(reply::bad_request);
+ return;
+ }
+
+ // Request path must be absolute and not contain "..".
+ if (request_path.empty() || request_path[0] != '/'
+ || request_path.find("..") != std::string::npos)
+ {
+ rep = reply::stock_reply(reply::bad_request);
+ return;
+ }
+
+ // If path ends in slash (i.e. is a directory) then add "index.html".
+ if (request_path[request_path.size() - 1] == '/')
+ {
+ request_path += "index.html";
+ }
+
+ // Determine the file extension.
+ std::size_t last_slash_pos = request_path.find_last_of("/");
+ std::size_t last_dot_pos = request_path.find_last_of(".");
+ std::string extension;
+ if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos)
+ {
+ extension = request_path.substr(last_dot_pos + 1);
+ }
+
+ // Open the file to send back.
+ std::string full_path = doc_root_ + request_path;
+ std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary);
+ if (!is)
+ {
+ rep = reply::stock_reply(reply::not_found);
+ return;
+ }
+
+ // Fill out the reply to be sent to the client.
+ rep.status = reply::ok;
+ char buf[512];
+ while (is.read(buf, sizeof(buf)).gcount() > 0)
+ rep.content.append(buf, is.gcount());
+ rep.headers.resize(2);
+ rep.headers[0].name = "Content-Length";
+ rep.headers[0].value = std::to_string(rep.content.size());
+ rep.headers[1].name = "Content-Type";
+ rep.headers[1].value = mime_types::extension_to_type(extension);
+}
+
+bool request_handler::url_decode(const std::string& in, std::string& out)
+{
+ out.clear();
+ out.reserve(in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ {
+ if (in[i] == '%')
+ {
+ if (i + 3 <= in.size())
+ {
+ int value = 0;
+ std::istringstream is(in.substr(i + 1, 2));
+ if (is >> std::hex >> value)
+ {
+ out += static_cast<char>(value);
+ i += 2;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (in[i] == '+')
+ {
+ out += ' ';
+ }
+ else
+ {
+ out += in[i];
+ }
+ }
+ return true;
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/request_handler.hpp b/3rdparty/asio/src/examples/cpp11/http/server/request_handler.hpp
new file mode 100644
index 00000000000..24cca33565a
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/request_handler.hpp
@@ -0,0 +1,47 @@
+//
+// request_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_REQUEST_HANDLER_HPP
+#define HTTP_REQUEST_HANDLER_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class request_handler
+{
+public:
+ request_handler(const request_handler&) = delete;
+ request_handler& operator=(const request_handler&) = delete;
+
+ /// Construct with a directory containing files to be served.
+ explicit request_handler(const std::string& doc_root);
+
+ /// Handle a request and produce a reply.
+ void handle_request(const request& req, reply& rep);
+
+private:
+ /// The directory containing the files to be served.
+ std::string doc_root_;
+
+ /// Perform URL-decoding on a string. Returns false if the encoding was
+ /// invalid.
+ static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HANDLER_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/request_parser.cpp b/3rdparty/asio/src/examples/cpp11/http/server/request_parser.cpp
new file mode 100644
index 00000000000..6812a558879
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/request_parser.cpp
@@ -0,0 +1,315 @@
+//
+// request_parser.cpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "request_parser.hpp"
+#include "request.hpp"
+
+namespace http {
+namespace server {
+
+request_parser::request_parser()
+ : state_(method_start)
+{
+}
+
+void request_parser::reset()
+{
+ state_ = method_start;
+}
+
+request_parser::result_type request_parser::consume(request& req, char input)
+{
+ switch (state_)
+ {
+ case method_start:
+ if (!is_char(input) || is_ctl(input) || is_tspecial(input))
+ {
+ return bad;
+ }
+ else
+ {
+ state_ = method;
+ req.method.push_back(input);
+ return indeterminate;
+ }
+ case method:
+ if (input == ' ')
+ {
+ state_ = uri;
+ return indeterminate;
+ }
+ else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
+ {
+ return bad;
+ }
+ else
+ {
+ req.method.push_back(input);
+ return indeterminate;
+ }
+ case uri:
+ if (input == ' ')
+ {
+ state_ = http_version_h;
+ return indeterminate;
+ }
+ else if (is_ctl(input))
+ {
+ return bad;
+ }
+ else
+ {
+ req.uri.push_back(input);
+ return indeterminate;
+ }
+ case http_version_h:
+ if (input == 'H')
+ {
+ state_ = http_version_t_1;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_t_1:
+ if (input == 'T')
+ {
+ state_ = http_version_t_2;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_t_2:
+ if (input == 'T')
+ {
+ state_ = http_version_p;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_p:
+ if (input == 'P')
+ {
+ state_ = http_version_slash;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_slash:
+ if (input == '/')
+ {
+ req.http_version_major = 0;
+ req.http_version_minor = 0;
+ state_ = http_version_major_start;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_major_start:
+ if (is_digit(input))
+ {
+ req.http_version_major = req.http_version_major * 10 + input - '0';
+ state_ = http_version_major;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_major:
+ if (input == '.')
+ {
+ state_ = http_version_minor_start;
+ return indeterminate;
+ }
+ else if (is_digit(input))
+ {
+ req.http_version_major = req.http_version_major * 10 + input - '0';
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_minor_start:
+ if (is_digit(input))
+ {
+ req.http_version_minor = req.http_version_minor * 10 + input - '0';
+ state_ = http_version_minor;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case http_version_minor:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_1;
+ return indeterminate;
+ }
+ else if (is_digit(input))
+ {
+ req.http_version_minor = req.http_version_minor * 10 + input - '0';
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case expecting_newline_1:
+ if (input == '\n')
+ {
+ state_ = header_line_start;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case header_line_start:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_3;
+ return indeterminate;
+ }
+ else if (!req.headers.empty() && (input == ' ' || input == '\t'))
+ {
+ state_ = header_lws;
+ return indeterminate;
+ }
+ else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
+ {
+ return bad;
+ }
+ else
+ {
+ req.headers.push_back(header());
+ req.headers.back().name.push_back(input);
+ state_ = header_name;
+ return indeterminate;
+ }
+ case header_lws:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_2;
+ return indeterminate;
+ }
+ else if (input == ' ' || input == '\t')
+ {
+ return indeterminate;
+ }
+ else if (is_ctl(input))
+ {
+ return bad;
+ }
+ else
+ {
+ state_ = header_value;
+ req.headers.back().value.push_back(input);
+ return indeterminate;
+ }
+ case header_name:
+ if (input == ':')
+ {
+ state_ = space_before_header_value;
+ return indeterminate;
+ }
+ else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
+ {
+ return bad;
+ }
+ else
+ {
+ req.headers.back().name.push_back(input);
+ return indeterminate;
+ }
+ case space_before_header_value:
+ if (input == ' ')
+ {
+ state_ = header_value;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case header_value:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_2;
+ return indeterminate;
+ }
+ else if (is_ctl(input))
+ {
+ return bad;
+ }
+ else
+ {
+ req.headers.back().value.push_back(input);
+ return indeterminate;
+ }
+ case expecting_newline_2:
+ if (input == '\n')
+ {
+ state_ = header_line_start;
+ return indeterminate;
+ }
+ else
+ {
+ return bad;
+ }
+ case expecting_newline_3:
+ return (input == '\n') ? good : bad;
+ default:
+ return bad;
+ }
+}
+
+bool request_parser::is_char(int c)
+{
+ return c >= 0 && c <= 127;
+}
+
+bool request_parser::is_ctl(int c)
+{
+ return (c >= 0 && c <= 31) || (c == 127);
+}
+
+bool request_parser::is_tspecial(int c)
+{
+ switch (c)
+ {
+ case '(': case ')': case '<': case '>': case '@':
+ case ',': case ';': case ':': case '\\': case '"':
+ case '/': case '[': case ']': case '?': case '=':
+ case '{': case '}': case ' ': case '\t':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool request_parser::is_digit(int c)
+{
+ return c >= '0' && c <= '9';
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/request_parser.hpp b/3rdparty/asio/src/examples/cpp11/http/server/request_parser.hpp
new file mode 100644
index 00000000000..643dd71c6f4
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/request_parser.hpp
@@ -0,0 +1,96 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_REQUEST_PARSER_HPP
+#define HTTP_REQUEST_PARSER_HPP
+
+#include <tuple>
+
+namespace http {
+namespace server {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser
+{
+public:
+ /// Construct ready to parse the request method.
+ request_parser();
+
+ /// Reset to initial parser state.
+ void reset();
+
+ /// Result of parse.
+ enum result_type { good, bad, indeterminate };
+
+ /// Parse some data. The enum return value is good when a complete request has
+ /// been parsed, bad if the data is invalid, indeterminate when more data is
+ /// required. The InputIterator return value indicates how much of the input
+ /// has been consumed.
+ template <typename InputIterator>
+ std::tuple<result_type, InputIterator> parse(request& req,
+ InputIterator begin, InputIterator end)
+ {
+ while (begin != end)
+ {
+ result_type result = consume(req, *begin++);
+ if (result == good || result == bad)
+ return std::make_tuple(result, begin);
+ }
+ return std::make_tuple(indeterminate, begin);
+ }
+
+private:
+ /// Handle the next character of input.
+ result_type consume(request& req, char input);
+
+ /// Check if a byte is an HTTP character.
+ static bool is_char(int c);
+
+ /// Check if a byte is an HTTP control character.
+ static bool is_ctl(int c);
+
+ /// Check if a byte is defined as an HTTP tspecial character.
+ static bool is_tspecial(int c);
+
+ /// Check if a byte is a digit.
+ static bool is_digit(int c);
+
+ /// The current state of the parser.
+ enum state
+ {
+ method_start,
+ method,
+ uri,
+ http_version_h,
+ http_version_t_1,
+ http_version_t_2,
+ http_version_p,
+ http_version_slash,
+ http_version_major_start,
+ http_version_major,
+ http_version_minor_start,
+ http_version_minor,
+ expecting_newline_1,
+ header_line_start,
+ header_lws,
+ header_name,
+ space_before_header_value,
+ header_value,
+ expecting_newline_2,
+ expecting_newline_3
+ } state_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_PARSER_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/server.cpp b/3rdparty/asio/src/examples/cpp11/http/server/server.cpp
new file mode 100644
index 00000000000..fa76a4def03
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/server.cpp
@@ -0,0 +1,94 @@
+//
+// server.cpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "server.hpp"
+#include <signal.h>
+#include <utility>
+
+namespace http {
+namespace server {
+
+server::server(const std::string& address, const std::string& port,
+ const std::string& doc_root)
+ : io_context_(1),
+ signals_(io_context_),
+ acceptor_(io_context_),
+ connection_manager_(),
+ request_handler_(doc_root)
+{
+ // Register to handle the signals that indicate when the server should exit.
+ // It is safe to register for the same signal multiple times in a program,
+ // provided all registration for the specified signal is made through Asio.
+ signals_.add(SIGINT);
+ signals_.add(SIGTERM);
+#if defined(SIGQUIT)
+ signals_.add(SIGQUIT);
+#endif // defined(SIGQUIT)
+
+ do_await_stop();
+
+ // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
+ asio::ip::tcp::resolver resolver(io_context_);
+ asio::ip::tcp::endpoint endpoint =
+ *resolver.resolve(address, port).begin();
+ acceptor_.open(endpoint.protocol());
+ acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor_.bind(endpoint);
+ acceptor_.listen();
+
+ do_accept();
+}
+
+void server::run()
+{
+ // The io_context::run() call will block until all asynchronous operations
+ // have finished. While the server is running, there is always at least one
+ // asynchronous operation outstanding: the asynchronous accept call waiting
+ // for new incoming connections.
+ io_context_.run();
+}
+
+void server::do_accept()
+{
+ acceptor_.async_accept(
+ [this](std::error_code ec, asio::ip::tcp::socket socket)
+ {
+ // Check whether the server was stopped by a signal before this
+ // completion handler had a chance to run.
+ if (!acceptor_.is_open())
+ {
+ return;
+ }
+
+ if (!ec)
+ {
+ connection_manager_.start(std::make_shared<connection>(
+ std::move(socket), connection_manager_, request_handler_));
+ }
+
+ do_accept();
+ });
+}
+
+void server::do_await_stop()
+{
+ signals_.async_wait(
+ [this](std::error_code /*ec*/, int /*signo*/)
+ {
+ // The server is stopped by cancelling all outstanding asynchronous
+ // operations. Once all operations have finished the io_context::run()
+ // call will exit.
+ acceptor_.close();
+ connection_manager_.stop_all();
+ });
+}
+
+} // namespace server
+} // namespace http
diff --git a/3rdparty/asio/src/examples/cpp11/http/server/server.hpp b/3rdparty/asio/src/examples/cpp11/http/server/server.hpp
new file mode 100644
index 00000000000..4f98f6cd07f
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/http/server/server.hpp
@@ -0,0 +1,64 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HTTP_SERVER_HPP
+#define HTTP_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include "connection.hpp"
+#include "connection_manager.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server {
+
+/// The top-level class of the HTTP server.
+class server
+{
+public:
+ server(const server&) = delete;
+ server& operator=(const server&) = delete;
+
+ /// Construct the server to listen on the specified TCP address and port, and
+ /// serve up files from the given directory.
+ explicit server(const std::string& address, const std::string& port,
+ const std::string& doc_root);
+
+ /// Run the server's io_context loop.
+ void run();
+
+private:
+ /// Perform an asynchronous accept operation.
+ void do_accept();
+
+ /// Wait for a request to stop the server.
+ void do_await_stop();
+
+ /// The io_context used to perform asynchronous operations.
+ asio::io_context io_context_;
+
+ /// The signal_set is used to register for process termination notifications.
+ asio::signal_set signals_;
+
+ /// Acceptor used to listen for incoming connections.
+ asio::ip::tcp::acceptor acceptor_;
+
+ /// The connection manager which owns all live connections.
+ connection_manager connection_manager_;
+
+ /// The handler for all incoming requests.
+ request_handler request_handler_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_SERVER_HPP
diff --git a/3rdparty/asio/src/examples/cpp11/iostreams/.gitignore b/3rdparty/asio/src/examples/cpp11/iostreams/.gitignore
new file mode 100644
index 00000000000..bc2b4f8f7fe
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/iostreams/.gitignore
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.o
+*.obj
+*.exe
+*_client
+*_server
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/iostreams/http_client.cpp b/3rdparty/asio/src/examples/cpp11/iostreams/http_client.cpp
new file mode 100644
index 00000000000..7972a67ecf9
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/iostreams/http_client.cpp
@@ -0,0 +1,91 @@
+//
+// http_client.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <iostream>
+#include <istream>
+#include <ostream>
+#include <string>
+#include <asio/ip/tcp.hpp>
+
+using asio::ip::tcp;
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cout << "Usage: http_client <server> <path>\n";
+ std::cout << "Example:\n";
+ std::cout << " http_client www.boost.org /LICENSE_1_0.txt\n";
+ return 1;
+ }
+
+ asio::ip::tcp::iostream s;
+
+ // The entire sequence of I/O operations must complete within 60 seconds.
+ // If an expiry occurs, the socket is automatically closed and the stream
+ // becomes bad.
+ s.expires_after(std::chrono::seconds(60));
+
+ // Establish a connection to the server.
+ s.connect(argv[1], "http");
+ if (!s)
+ {
+ std::cout << "Unable to connect: " << s.error().message() << "\n";
+ return 1;
+ }
+
+ // Send the request. We specify the "Connection: close" header so that the
+ // server will close the socket after transmitting the response. This will
+ // allow us to treat all data up until the EOF as the content.
+ s << "GET " << argv[2] << " HTTP/1.0\r\n";
+ s << "Host: " << argv[1] << "\r\n";
+ s << "Accept: */*\r\n";
+ s << "Connection: close\r\n\r\n";
+
+ // By default, the stream is tied with itself. This means that the stream
+ // automatically flush the buffered output before attempting a read. It is
+ // not necessary not explicitly flush the stream at this point.
+
+ // Check that response is OK.
+ std::string http_version;
+ s >> http_version;
+ unsigned int status_code;
+ s >> status_code;
+ std::string status_message;
+ std::getline(s, status_message);
+ if (!s || http_version.substr(0, 5) != "HTTP/")
+ {
+ std::cout << "Invalid response\n";
+ return 1;
+ }
+ if (status_code != 200)
+ {
+ std::cout << "Response returned with status code " << status_code << "\n";
+ return 1;
+ }
+
+ // Process the response headers, which are terminated by a blank line.
+ std::string header;
+ while (std::getline(s, header) && header != "\r")
+ std::cout << header << "\n";
+ std::cout << "\n";
+
+ // Write the remaining data to output.
+ std::cout << s.rdbuf();
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/spawn/.gitignore b/3rdparty/asio/src/examples/cpp11/spawn/.gitignore
new file mode 100644
index 00000000000..6b8a121e099
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/spawn/.gitignore
@@ -0,0 +1,12 @@
+.deps
+.dirstamp
+parallel_grep
+*.o
+*.obj
+*.exe
+*_server
+*_client
+*.ilk
+*.manifest
+*.pdb
+*.tds
diff --git a/3rdparty/asio/src/examples/cpp11/spawn/echo_server.cpp b/3rdparty/asio/src/examples/cpp11/spawn/echo_server.cpp
new file mode 100644
index 00000000000..5397a4efe22
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/spawn/echo_server.cpp
@@ -0,0 +1,108 @@
+//
+// echo_server.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <asio/io_context.hpp>
+#include <asio/ip/tcp.hpp>
+#include <asio/spawn.hpp>
+#include <asio/steady_timer.hpp>
+#include <asio/write.hpp>
+#include <iostream>
+#include <memory>
+
+using asio::ip::tcp;
+
+class session : public std::enable_shared_from_this<session>
+{
+public:
+ explicit session(tcp::socket socket)
+ : socket_(std::move(socket)),
+ timer_(socket_.get_io_context()),
+ strand_(socket_.get_io_context())
+ {
+ }
+
+ void go()
+ {
+ auto self(shared_from_this());
+ asio::spawn(strand_,
+ [this, self](asio::yield_context yield)
+ {
+ try
+ {
+ char data[128];
+ for (;;)
+ {
+ timer_.expires_from_now(std::chrono::seconds(10));
+ std::size_t n = socket_.async_read_some(asio::buffer(data), yield);
+ asio::async_write(socket_, asio::buffer(data, n), yield);
+ }
+ }
+ catch (std::exception& e)
+ {
+ socket_.close();
+ timer_.cancel();
+ }
+ });
+
+ asio::spawn(strand_,
+ [this, self](asio::yield_context yield)
+ {
+ while (socket_.is_open())
+ {
+ asio::error_code ignored_ec;
+ timer_.async_wait(yield[ignored_ec]);
+ if (timer_.expires_from_now() <= std::chrono::seconds(0))
+ socket_.close();
+ }
+ });
+ }
+
+private:
+ tcp::socket socket_;
+ asio::steady_timer timer_;
+ asio::io_context::strand strand_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: echo_server <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ asio::spawn(io_context,
+ [&](asio::yield_context yield)
+ {
+ tcp::acceptor acceptor(io_context,
+ tcp::endpoint(tcp::v4(), std::atoi(argv[1])));
+
+ for (;;)
+ {
+ asio::error_code ec;
+ tcp::socket socket(io_context);
+ acceptor.async_accept(socket, yield[ec]);
+ if (!ec) std::make_shared<session>(std::move(socket))->go();
+ }
+ });
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/3rdparty/asio/src/examples/cpp11/spawn/parallel_grep.cpp b/3rdparty/asio/src/examples/cpp11/spawn/parallel_grep.cpp
new file mode 100644
index 00000000000..954d9472bbe
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/spawn/parallel_grep.cpp
@@ -0,0 +1,84 @@
+//
+// parallel_grep.cpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <asio/dispatch.hpp>
+#include <asio/post.hpp>
+#include <asio/spawn.hpp>
+#include <asio/strand.hpp>
+#include <asio/thread_pool.hpp>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+using asio::dispatch;
+using asio::spawn;
+using asio::strand;
+using asio::thread_pool;
+using asio::yield_context;
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc < 2)
+ {
+ std::cerr << "Usage: parallel_grep <string> <files...>\n";
+ return 1;
+ }
+
+ // We use a fixed size pool of threads for reading the input files. The
+ // number of threads is automatically determined based on the number of
+ // CPUs available in the system.
+ thread_pool pool;
+
+ // To prevent the output from being garbled, we use a strand to synchronise
+ // printing.
+ strand<thread_pool::executor_type> output_strand(pool.get_executor());
+
+ // Spawn a new coroutine for each file specified on the command line.
+ std::string search_string = argv[1];
+ for (int argn = 2; argn < argc; ++argn)
+ {
+ std::string input_file = argv[argn];
+ spawn(pool,
+ [=](yield_context yield)
+ {
+ std::ifstream is(input_file.c_str());
+ std::string line;
+ std::size_t line_num = 0;
+ while (std::getline(is, line))
+ {
+ // If we find a match, send a message to the output.
+ if (line.find(search_string) != std::string::npos)
+ {
+ dispatch(output_strand,
+ [=]
+ {
+ std::cout << input_file << ':' << line << std::endl;
+ });
+ }
+
+ // Every so often we yield control to another coroutine.
+ if (++line_num % 10 == 0)
+ post(yield);
+ }
+ });
+ }
+
+ // Join the thread pool to wait for all the spawned tasks to complete.
+ pool.join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}