diff --git a/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp b/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp index dd52526a..18dd47c4 100644 --- a/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp +++ b/Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp @@ -17,7 +17,7 @@ class tasks_processor: public tp_network::tasks_processor { ); } - // one thread is the current thread + // First thread is the current thread. -- threads_count; boost::asio::io_service& ios = get_ios(); diff --git a/Chapter06/flat/01_tasks_processor_base/01_tasks_processor_base.pro b/Chapter06/flat/01_tasks_processor_base/01_tasks_processor_base.pro new file mode 100644 index 00000000..af7e6204 --- /dev/null +++ b/Chapter06/flat/01_tasks_processor_base/01_tasks_processor_base.pro @@ -0,0 +1,6 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/01_tasks_processor_base/main.cpp b/Chapter06/flat/01_tasks_processor_base/main.cpp new file mode 100644 index 00000000..a1e32772 --- /dev/null +++ b/Chapter06/flat/01_tasks_processor_base/main.cpp @@ -0,0 +1,125 @@ +// Amost all the code for this example is in this header + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + +using namespace tp_base; + +int func_test() { + static int counter = 0; + ++ counter; + boost::this_thread::interruption_point(); + + switch (counter) { + case 3: + throw std::logic_error("Just checking"); + + case 10: + // Emulation of thread interruption. + // Caught inside task_wrapped and does not stop execution. + throw boost::thread_interrupted(); + + case 90: + // Stopping the tasks_processor. + tasks_processor::stop(); + } + + return counter; +} + +int main () { + for (std::size_t i = 0; i < 100; ++i) { + tasks_processor::push_task(&func_test); + } + + // Processing was not started. + assert(func_test() == 1); + + // We can also use lambda as a task. +#ifndef BOOST_NO_CXX11_LAMBDAS + // Counting 2 + 2 asynchronously. + int sum = 0; + tasks_processor::push_task( + [&sum]() { sum = 2 + 2; } + ); + // Processing was not started. + assert(sum == 0); +#endif + + // Does not throw, but blocks till + // one of the tasks it is owning + // calls tasks_processor::stop(). + tasks_processor::start(); + assert(func_test() == 91); +} diff --git a/Chapter06/flat/02_tasks_processor_timers/02_tasks_processor_timers.pro b/Chapter06/flat/02_tasks_processor_timers/02_tasks_processor_timers.pro new file mode 100644 index 00000000..f98665fa --- /dev/null +++ b/Chapter06/flat/02_tasks_processor_timers/02_tasks_processor_timers.pro @@ -0,0 +1,7 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +QMAKE_CXXFLAGS += $$CPP11FLAG +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/02_tasks_processor_timers/main.cpp b/Chapter06/flat/02_tasks_processor_timers/main.cpp new file mode 100644 index 00000000..a751a143 --- /dev/null +++ b/Chapter06/flat/02_tasks_processor_timers/main.cpp @@ -0,0 +1,189 @@ +// Almost all the code for this recipe +// is in this header file. + + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + + +#include +#include +#include +#include // std::unique_ptr +#include + +namespace detail { + + template + struct timer_task { + private: + std::unique_ptr timer_; + task_wrapped task_; + + public: + explicit timer_task( + std::unique_ptr timer, + const Functor& task_unwrapped) + : timer_(std::move(timer)) + , task_(task_unwrapped) + {} + + void operator()(const boost::system::error_code& error) const { + if (!error) { + task_(); + } else { + std::cerr << error << '\n'; + } + } + }; + +} // namespace detail + +namespace tp_timers { + +class tasks_processor: public tp_base::tasks_processor { +public: + + template + static void run_delayed(Time duration_or_time, const Functor& f) { + std::unique_ptr timer( + new boost::asio::deadline_timer( + get_ios(), duration_or_time + ) + ); + + boost::asio::deadline_timer& timer_ref = *timer; + + timer_ref.async_wait( + detail::timer_task( + std::move(timer), + f + ) + ); + } +}; + +} // namespace tp_timers + +using namespace tp_timers; + +struct test_functor { + int& i_; + + explicit test_functor(int& i); + + void operator()() const { + i_ = 1; + tasks_processor::stop(); + } +}; + +void test_func1(); + +#include + +int main () { + const int seconds_to_wait = 3; + int i = 0; + + tasks_processor::run_delayed( + boost::posix_time::seconds(seconds_to_wait), + test_functor(i) + ); + + tasks_processor::run_delayed( + boost::posix_time::from_time_t(time(NULL) + 1), + &test_func1 + ); + + int t1 = static_cast(time(NULL)); + assert(i == 0); + + // Blocks till one of the tasks + // calls tasks_processor::stop(). + tasks_processor::start(); + + assert(i == 1); + int t2 = static_cast(time(NULL)); + assert(t2 - t1 >= seconds_to_wait); +} + + +test_functor::test_functor(int& i) + : i_(i) +{} + +void test_func1() { + throw std::logic_error("It works!"); +} diff --git a/Chapter06/flat/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro b/Chapter06/flat/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro new file mode 100644 index 00000000..67db8e60 --- /dev/null +++ b/Chapter06/flat/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro @@ -0,0 +1,8 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp + +QMAKE_CXXFLAGS += $$CPP11FLAG +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/04_tasks_processor_network_accept/main.cpp b/Chapter06/flat/04_tasks_processor_network_accept/main.cpp new file mode 100644 index 00000000..62688bf4 --- /dev/null +++ b/Chapter06/flat/04_tasks_processor_network_accept/main.cpp @@ -0,0 +1,460 @@ +// Big part of code for this recipe +// in in this header: + + + + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + + +#include +#include +#include +#include // std::unique_ptr +#include + +namespace detail { + + template + struct timer_task { + private: + std::unique_ptr timer_; + task_wrapped task_; + + public: + explicit timer_task( + std::unique_ptr timer, + const Functor& task_unwrapped) + : timer_(std::move(timer)) + , task_(task_unwrapped) + {} + + void operator()(const boost::system::error_code& error) const { + if (!error) { + task_(); + } else { + std::cerr << error << '\n'; + } + } + }; + +} // namespace detail + +namespace tp_timers { + +class tasks_processor: public tp_base::tasks_processor { +public: + + template + static void run_delayed(Time duration_or_time, const Functor& f) { + std::unique_ptr timer( + new boost::asio::deadline_timer( + get_ios(), duration_or_time + ) + ); + + boost::asio::deadline_timer& timer_ref = *timer; + + timer_ref.async_wait( + detail::timer_task( + std::move(timer), + f + ) + ); + } +}; + +} // namespace tp_timers + + +#include +#include + +struct connection_with_data: boost::noncopyable { + boost::asio::ip::tcp::socket socket; + std::string data; + + explicit connection_with_data(boost::asio::io_service& ios) + : socket(ios) + {} + + void shutdown() { + if (!socket.is_open()) { + return; + } + + boost::system::error_code ignore; + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore); + socket.close(ignore); + } + + ~connection_with_data() { + shutdown(); + } +}; + + +#include // std::unique_ptr + +typedef std::unique_ptr connection_ptr; + + +template +struct task_wrapped_with_connection { +private: + connection_ptr c_; + T task_unwrapped_; + +public: + explicit task_wrapped_with_connection(connection_ptr&& c, const T& f) + : c_(std::move(c)) + , task_unwrapped_(f) + {} + + void operator()(const boost::system::error_code& error, std::size_t bytes_count) { + const auto lambda = [this, &error, bytes_count]() { + this->c_->data.resize(bytes_count); + this->task_unwrapped_(std::move(this->c_), error); + }; + + const auto task = detail::make_task_wrapped(lambda); + + task(); + } +}; + +#include + +template +struct task_wrapped_with_connection; + +template +void async_write_data(connection_ptr&& c, const Functor& f) { + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + + boost::asio::async_write( + s, + boost::asio::buffer(d), + task_wrapped_with_connection(std::move(c), f) + ); +} + +#include + +template +void async_read_data(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes) { + c->data.resize(at_least_bytes); + + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + char* p = (d.empty() ? 0 : &d[0]); + + boost::asio::async_read( + s, + boost::asio::buffer(p, d.size()), + task_wrapped_with_connection(std::move(c), f) + ); +} + + +template +void async_read_dataat_least(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes, std::size_t at_most = 4095) { + std::string& d = c->data; + d.resize(at_most); + char* p = (at_most == 0 ? 0 : &d[0]); + + boost::asio::ip::tcp::socket& s = c->socket; + + boost::asio::async_read( + s, + boost::asio::buffer(p, at_most), + boost::asio::transfer_at_least(at_least_bytes), + task_wrapped_with_connection(std::move(c), f) + ); +} + +namespace tp_network_client { + +class tasks_processor: public tp_timers::tasks_processor { + // ... + +public: + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network_cleint + + +#include +namespace tp_network { + +class tasks_processor: public tp_network_client::tasks_processor { + typedef boost::asio::ip::tcp::acceptor acceptor_t; + typedef boost::function on_accpet_func_t; + + struct tcp_listener { + acceptor_t acceptor_; + const on_accpet_func_t func_; + connection_ptr new_c_; + + template + tcp_listener( + boost::asio::io_service& io_service, + unsigned short port, + const Functor& task_unwrapped) + : acceptor_(io_service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::tcp::v4(), port + )) + , func_(task_unwrapped) + {} + }; + typedef std::unique_ptr listener_ptr; + + struct handle_accept { + listener_ptr listener; + + explicit handle_accept(listener_ptr&& l) + : listener(std::move(l)) + {} + + void operator()(const boost::system::error_code& error) { + task_wrapped_with_connection task(std::move(listener->new_c_), listener->func_); + if (error) { + std::cerr << error << '\n'; + } + + start_accepting_connection(std::move(listener)); + task(error, 0); + } + }; + + static void start_accepting_connection(listener_ptr&& listener) { + if (!listener->acceptor_.is_open()) { + return; + } + + listener->new_c_.reset( + new connection_with_data(listener->acceptor_.get_io_service()) + ); + + boost::asio::ip::tcp::socket& s = listener->new_c_->socket; + acceptor_t& a = listener->acceptor_; + a.async_accept( + s, + tasks_processor::handle_accept(std::move(listener)) + ); + } + +public: + template + static void add_listener(unsigned short port_num, const Functor& f) { + std::unique_ptr listener( + new tcp_listener(get_ios(), port_num, f) + ); + + start_accepting_connection(std::move(listener)); + } + + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network + +// Helper heade file +extern bool g_authed; +const unsigned short g_port_num = 65001; + +void send_auth(); +using namespace tp_network; + +class authorizer { +public: + static void on_connection_accpet(connection_ptr&& connection, const boost::system::error_code& error) { + assert(!error); + async_read_dataat_least(std::move(connection), &authorizer::on_datarecieve, 1); + } + + static void on_datarecieve(connection_ptr&& connection, const boost::system::error_code& error) { + if (error) { + std::cerr << "authorizer.on_datarecieve: error during recieving response: " << error << '\n'; + assert(false); + } + + if (connection->data.size() == 0) { + std::cerr << "authorizer.on_datarecieve: zero bytes recieved\n"; + assert(false); + } + + assert(connection->data == "auth_name"); + + // We have data and now we can + // do some authorization. + // ... + connection->data = "OK"; + // ... + + // Now we have response in `connection->data` and it's time to send it. + async_write_data(std::move(connection), &authorizer::on_datasend); + } + + static void on_datasend(connection_ptr&& connection, const boost::system::error_code& error) { + if (error) { + std::cerr << "authorizer.on_datasend: error during sending response: " << error << '\n'; + assert(false); + } + + connection->shutdown(); + } +}; + + +int main() { + tasks_processor::run_delayed(boost::posix_time::seconds(1), &send_auth); + tasks_processor::add_listener(g_port_num, &authorizer::on_connection_accpet); + assert(!g_authed); + + tasks_processor::start(); + assert(g_authed); +} +// Big part of code for this recipe +// in in this header: + +bool g_authed = false; + +void process_server_response( + connection_ptr&& soc, + const boost::system::error_code& err) +{ + if (err && err != boost::asio::error::eof) { + std::cerr << "process_server_response: Client error on receive: " << err.message() << '\n'; + assert(false); + } + + if (soc->data.size() != 2) { + std::cerr << "process_server_response: wrong bytes count\n"; + assert(false); + } + + if (soc->data != "OK") { + std::cerr << "process_server_response: wrong response: " << soc->data << '\n'; + assert(false); + } + + g_authed = true; + soc->shutdown(); + tasks_processor::stop(); +} + +void receive_auth_response(connection_ptr&& soc, const boost::system::error_code& err) { + if (err) { + std::cerr << "receive_auth_response: error on sending data: " << err.message() << '\n'; + assert(false); + } + + async_read_data( + std::move(soc), + &process_server_response, + 2 + ); +} + +void send_auth() { + connection_ptr soc = tasks_processor::create_connection("127.0.0.1", g_port_num); + soc->data = "auth_name"; + + async_write_data( + std::move(soc), + &receive_auth_response + ); +} diff --git a/Chapter06/flat/05_tasks_processor_multithread/05_tasks_processor_multithread.pro b/Chapter06/flat/05_tasks_processor_multithread/05_tasks_processor_multithread.pro new file mode 100644 index 00000000..f98665fa --- /dev/null +++ b/Chapter06/flat/05_tasks_processor_multithread/05_tasks_processor_multithread.pro @@ -0,0 +1,7 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +QMAKE_CXXFLAGS += $$CPP11FLAG +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/05_tasks_processor_multithread/main.cpp b/Chapter06/flat/05_tasks_processor_multithread/main.cpp new file mode 100644 index 00000000..a567a3ec --- /dev/null +++ b/Chapter06/flat/05_tasks_processor_multithread/main.cpp @@ -0,0 +1,405 @@ +// See this header some code of this recipe + + + + + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + + +#include +#include +#include +#include // std::unique_ptr +#include + +namespace detail { + + template + struct timer_task { + private: + std::unique_ptr timer_; + task_wrapped task_; + + public: + explicit timer_task( + std::unique_ptr timer, + const Functor& task_unwrapped) + : timer_(std::move(timer)) + , task_(task_unwrapped) + {} + + void operator()(const boost::system::error_code& error) const { + if (!error) { + task_(); + } else { + std::cerr << error << '\n'; + } + } + }; + +} // namespace detail + +namespace tp_timers { + +class tasks_processor: public tp_base::tasks_processor { +public: + + template + static void run_delayed(Time duration_or_time, const Functor& f) { + std::unique_ptr timer( + new boost::asio::deadline_timer( + get_ios(), duration_or_time + ) + ); + + boost::asio::deadline_timer& timer_ref = *timer; + + timer_ref.async_wait( + detail::timer_task( + std::move(timer), + f + ) + ); + } +}; + +} // namespace tp_timers + + +#include +#include + +struct connection_with_data: boost::noncopyable { + boost::asio::ip::tcp::socket socket; + std::string data; + + explicit connection_with_data(boost::asio::io_service& ios) + : socket(ios) + {} + + void shutdown() { + if (!socket.is_open()) { + return; + } + + boost::system::error_code ignore; + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore); + socket.close(ignore); + } + + ~connection_with_data() { + shutdown(); + } +}; + + +#include // std::unique_ptr + +typedef std::unique_ptr connection_ptr; + + +template +struct task_wrapped_with_connection { +private: + connection_ptr c_; + T task_unwrapped_; + +public: + explicit task_wrapped_with_connection(connection_ptr&& c, const T& f) + : c_(std::move(c)) + , task_unwrapped_(f) + {} + + void operator()(const boost::system::error_code& error, std::size_t bytes_count) { + const auto lambda = [this, &error, bytes_count]() { + this->c_->data.resize(bytes_count); + this->task_unwrapped_(std::move(this->c_), error); + }; + + const auto task = detail::make_task_wrapped(lambda); + + task(); + } +}; + +#include + +template +struct task_wrapped_with_connection; + +template +void async_write_data(connection_ptr&& c, const Functor& f) { + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + + boost::asio::async_write( + s, + boost::asio::buffer(d), + task_wrapped_with_connection(std::move(c), f) + ); +} + +#include + +template +void async_read_data(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes) { + c->data.resize(at_least_bytes); + + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + char* p = (d.empty() ? 0 : &d[0]); + + boost::asio::async_read( + s, + boost::asio::buffer(p, d.size()), + task_wrapped_with_connection(std::move(c), f) + ); +} + + +template +void async_read_dataat_least(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes, std::size_t at_most = 4095) { + std::string& d = c->data; + d.resize(at_most); + char* p = (at_most == 0 ? 0 : &d[0]); + + boost::asio::ip::tcp::socket& s = c->socket; + + boost::asio::async_read( + s, + boost::asio::buffer(p, at_most), + boost::asio::transfer_at_least(at_least_bytes), + task_wrapped_with_connection(std::move(c), f) + ); +} + +namespace tp_network_client { + +class tasks_processor: public tp_timers::tasks_processor { + // ... + +public: + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network_cleint + + +#include +namespace tp_network { + +class tasks_processor: public tp_network_client::tasks_processor { + typedef boost::asio::ip::tcp::acceptor acceptor_t; + typedef boost::function on_accpet_func_t; + + struct tcp_listener { + acceptor_t acceptor_; + const on_accpet_func_t func_; + connection_ptr new_c_; + + template + tcp_listener( + boost::asio::io_service& io_service, + unsigned short port, + const Functor& task_unwrapped) + : acceptor_(io_service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::tcp::v4(), port + )) + , func_(task_unwrapped) + {} + }; + typedef std::unique_ptr listener_ptr; + + struct handle_accept { + listener_ptr listener; + + explicit handle_accept(listener_ptr&& l) + : listener(std::move(l)) + {} + + void operator()(const boost::system::error_code& error) { + task_wrapped_with_connection task(std::move(listener->new_c_), listener->func_); + if (error) { + std::cerr << error << '\n'; + } + + start_accepting_connection(std::move(listener)); + task(error, 0); + } + }; + + static void start_accepting_connection(listener_ptr&& listener) { + if (!listener->acceptor_.is_open()) { + return; + } + + listener->new_c_.reset( + new connection_with_data(listener->acceptor_.get_io_service()) + ); + + boost::asio::ip::tcp::socket& s = listener->new_c_->socket; + acceptor_t& a = listener->acceptor_; + a.async_accept( + s, + tasks_processor::handle_accept(std::move(listener)) + ); + } + +public: + template + static void add_listener(unsigned short port_num, const Functor& f) { + std::unique_ptr listener( + new tcp_listener(get_ios(), port_num, f) + ); + + start_accepting_connection(std::move(listener)); + } + + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network + + +#include + +namespace tp_multithread { + +class tasks_processor: public tp_network::tasks_processor { +public: + // Default value will attempt to guess optimal count of threads. + static void start_multiple(std::size_t threads_count = 0) { + if (!threads_count) { + threads_count = (std::max)(static_cast( + boost::thread::hardware_concurrency()), 1 + ); + } + + // one thread is the current thread + -- threads_count; + + boost::asio::io_service& ios = get_ios(); + boost::thread_group tg; + for (std::size_t i = 0; i < threads_count; ++i) { + tg.create_thread([&ios]() { ios.run(); }); + } + + ios.run(); + tg.join_all(); + } +}; + +} // namespace tp_multithread + +using namespace tp_multithread; + +const std::size_t threads_count = 5; +#include +boost::barrier g_barrier(threads_count); + +void multythread_test() { + g_barrier.wait(); + tasks_processor::stop(); +} + +int main() { + for (std::size_t i = 0; i < threads_count; ++i) { + tasks_processor::push_task(&multythread_test); + } + time_t t1 = time(NULL); + tasks_processor::start_multiple(threads_count); + time_t t2 = time(NULL); + // One additional second for some io_service and OS delays + assert(t2 - t1 < 1); +} diff --git a/Chapter06/flat/07_nonblocking_barrier/07_nonblocking_barrier.pro b/Chapter06/flat/07_nonblocking_barrier/07_nonblocking_barrier.pro new file mode 100644 index 00000000..af7e6204 --- /dev/null +++ b/Chapter06/flat/07_nonblocking_barrier/07_nonblocking_barrier.pro @@ -0,0 +1,6 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/07_nonblocking_barrier/main.cpp b/Chapter06/flat/07_nonblocking_barrier/main.cpp new file mode 100644 index 00000000..98c9b9e6 --- /dev/null +++ b/Chapter06/flat/07_nonblocking_barrier/main.cpp @@ -0,0 +1,204 @@ +#include +static const std::size_t data_length = 10000; + +#include +struct vector_type : public boost::array { + void* alignment; +}; + +typedef boost::array data_t; + +void fill_data(vector_type& data); +void compute_send_data(data_t& data); + +#include +void runner(std::size_t thread_index, boost::barrier& data_barrier, data_t& data) { + for (std::size_t i = 0; i < 1000; ++ i) { + fill_data(data.at(thread_index)); + data_barrier.wait(); + + if (!thread_index) { + compute_send_data(data); + } + data_barrier.wait(); + } +} + +void clever_implementation(); + +#include +int main() { + + // Initing barriers + boost::barrier data_barrier(data_t::static_size); + + // Initing data + data_t data; + + // Run on 4 threads + boost::thread_group tg; + for (std::size_t i = 0; i < data_t::static_size; ++i) { + tg.create_thread(boost::bind( + &runner, + i, + boost::ref(data_barrier), + boost::ref(data) + )); + } + + tg.join_all(); + + // Clever implementation + clever_implementation(); +} + + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + +using namespace tp_base; + +#include +typedef boost::atomic atomic_count_t; + +void clever_runner( + std::size_t thread_index, + std::size_t iteration, + atomic_count_t& counter, + data_t& data) +{ + fill_data(data.at(thread_index)); + + if (++counter == data_t::static_size) { + compute_send_data(data); + + ++ iteration; + if (iteration == 1000) { + // exiting, because 1000 iterations are done + tasks_processor::stop(); + return; + } + + counter = 0; + for (std::size_t i = 0; i < data_t::static_size; ++ i) { + tasks_processor::push_task(boost::bind( + clever_runner, + i, + iteration, + boost::ref(counter), + boost::ref(data) + )); + } + } +} + +void clever_implementation() { + // Initing counter + atomic_count_t counter(0); + + // Initing data + data_t data; + + // Run on 4 threads. + for (std::size_t i = 0; i < data_t::static_size; ++i) { + tasks_processor::push_task(boost::bind( + &clever_runner, + i, + 0, // first run + boost::ref(counter), + boost::ref(data) + )); + } + + tasks_processor::start(); +} + + +// functions implementation + +void fill_data(vector_type& data) { + for (std::size_t i = 0; i < vector_type::static_size; ++ i) { + data[i] = i; + data.alignment = 0; + } +} + +void compute_send_data(data_t& data) { + for (std::size_t i = 0; i < vector_type::static_size; ++i) { + for (std::size_t j = 0; j < data_t::static_size; ++j) { + assert(data[j][i] == i); + data[0][i] *= data[j][i]; + } + } +} diff --git a/Chapter06/flat/08_exception_ptr/08_exception_ptr.pro b/Chapter06/flat/08_exception_ptr/08_exception_ptr.pro new file mode 100644 index 00000000..af7e6204 --- /dev/null +++ b/Chapter06/flat/08_exception_ptr/08_exception_ptr.pro @@ -0,0 +1,6 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/08_exception_ptr/main.cpp b/Chapter06/flat/08_exception_ptr/main.cpp new file mode 100644 index 00000000..e06b2d35 --- /dev/null +++ b/Chapter06/flat/08_exception_ptr/main.cpp @@ -0,0 +1,161 @@ + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + +using namespace tp_base; + +#include +#include +void func_test2(); // Forward declaration + +struct process_exception { + boost::exception_ptr exc_; + + explicit process_exception(const boost::exception_ptr& exc) + : exc_(exc) + {} + + void operator()() const { + try { + boost::rethrow_exception(exc_); + } catch (const boost::bad_lexical_cast& /*e*/) { + std::cout << "Lexical cast exception detected\n" << std::endl; + + // Pushing another task to execute + tasks_processor::push_task(&func_test2); + } catch (...) { + std::cout << "Can not handle such exceptions:\n" + << boost::current_exception_diagnostic_information() + << std::endl; + + // Stopping + tasks_processor::stop(); + } + } +}; + +void func_test1() { + try { + boost::lexical_cast("oops!"); + } catch (...) { + tasks_processor::push_task( + process_exception(boost::current_exception()) + ); + } +} + +#include +void func_test2() { + try { + // Some code goes here + BOOST_THROW_EXCEPTION(std::logic_error("Some fatal logic error")); + // Some code goes here + } catch (...) { + tasks_processor::push_task( + process_exception(boost::current_exception()) + ); + } +} + +void run_throw(boost::exception_ptr& ptr) { + try { + // A lot of code goes here + } catch (...) { + ptr = boost::current_exception(); + } +} + +int main () { + tasks_processor::push_task(&func_test1); + tasks_processor::start(); + + + boost::exception_ptr ptr; + // Do some work in parallel + boost::thread t( + &run_throw, + boost::ref(ptr) + ); + + // Some code goes here + // ... + + t.join(); + + // Chacking for exception + if (ptr) { + // Exception occured in thread + boost::rethrow_exception(ptr); + } +} diff --git a/Chapter06/flat/09_tasks_processor_signals/09_tasks_processor_signals.pro b/Chapter06/flat/09_tasks_processor_signals/09_tasks_processor_signals.pro new file mode 100644 index 00000000..f98665fa --- /dev/null +++ b/Chapter06/flat/09_tasks_processor_signals/09_tasks_processor_signals.pro @@ -0,0 +1,7 @@ +if (!include(../../../config.txt)) { + error("Failed to open config.txt") +} + +SOURCES += main.cpp +QMAKE_CXXFLAGS += $$CPP11FLAG +!msvc:LIBS += -lboost_thread -lboost_system diff --git a/Chapter06/flat/09_tasks_processor_signals/main.cpp b/Chapter06/flat/09_tasks_processor_signals/main.cpp new file mode 100644 index 00000000..eac83985 --- /dev/null +++ b/Chapter06/flat/09_tasks_processor_signals/main.cpp @@ -0,0 +1,476 @@ +// Almost all the code for this recipe +// is in this header file + + + + + + +#include + +namespace detail { + +template +struct task_wrapped { +private: + T task_unwrapped_; + +public: + explicit task_wrapped(const T& f) + : task_unwrapped_(f) + {} + + void operator()() const { + // Resetting interruption. + try { + boost::this_thread::interruption_point(); + } catch(const boost::thread_interrupted&){} + + try { + // Executing task. + task_unwrapped_(); + } catch (const std::exception& e) { + std::cerr<< "Exception: " << e.what() << '\n'; + } catch (const boost::thread_interrupted&) { + std::cerr<< "Thread interrupted\n"; + } catch (...) { + std::cerr<< "Unknown exception\n"; + } + } +}; + +} // namespace detail + +namespace detail { + +template +task_wrapped make_task_wrapped(const T& task_unwrapped) { + return task_wrapped(task_unwrapped); +} + +} // namespace detail + + +#include +namespace tp_base { + +class tasks_processor: private boost::noncopyable { +protected: + static boost::asio::io_service& get_ios() { + static boost::asio::io_service ios; + static boost::asio::io_service::work work(ios); + + return ios; + } + +public: + template + static void push_task(const T& task_unwrapped) { + get_ios().post(detail::make_task_wrapped(task_unwrapped)); + } + + static void start() { + get_ios().run(); + } + + static void stop() { + get_ios().stop(); + } +}; // tasks_processor + +} // namespace tp_base + + +#include +#include +#include +#include // std::unique_ptr +#include + +namespace detail { + + template + struct timer_task { + private: + std::unique_ptr timer_; + task_wrapped task_; + + public: + explicit timer_task( + std::unique_ptr timer, + const Functor& task_unwrapped) + : timer_(std::move(timer)) + , task_(task_unwrapped) + {} + + void operator()(const boost::system::error_code& error) const { + if (!error) { + task_(); + } else { + std::cerr << error << '\n'; + } + } + }; + +} // namespace detail + +namespace tp_timers { + +class tasks_processor: public tp_base::tasks_processor { +public: + + template + static void run_delayed(Time duration_or_time, const Functor& f) { + std::unique_ptr timer( + new boost::asio::deadline_timer( + get_ios(), duration_or_time + ) + ); + + boost::asio::deadline_timer& timer_ref = *timer; + + timer_ref.async_wait( + detail::timer_task( + std::move(timer), + f + ) + ); + } +}; + +} // namespace tp_timers + + +#include +#include + +struct connection_with_data: boost::noncopyable { + boost::asio::ip::tcp::socket socket; + std::string data; + + explicit connection_with_data(boost::asio::io_service& ios) + : socket(ios) + {} + + void shutdown() { + if (!socket.is_open()) { + return; + } + + boost::system::error_code ignore; + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore); + socket.close(ignore); + } + + ~connection_with_data() { + shutdown(); + } +}; + + +#include // std::unique_ptr + +typedef std::unique_ptr connection_ptr; + + +template +struct task_wrapped_with_connection { +private: + connection_ptr c_; + T task_unwrapped_; + +public: + explicit task_wrapped_with_connection(connection_ptr&& c, const T& f) + : c_(std::move(c)) + , task_unwrapped_(f) + {} + + void operator()(const boost::system::error_code& error, std::size_t bytes_count) { + const auto lambda = [this, &error, bytes_count]() { + this->c_->data.resize(bytes_count); + this->task_unwrapped_(std::move(this->c_), error); + }; + + const auto task = detail::make_task_wrapped(lambda); + + task(); + } +}; + +#include + +template +struct task_wrapped_with_connection; + +template +void async_write_data(connection_ptr&& c, const Functor& f) { + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + + boost::asio::async_write( + s, + boost::asio::buffer(d), + task_wrapped_with_connection(std::move(c), f) + ); +} + +#include + +template +void async_read_data(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes) { + c->data.resize(at_least_bytes); + + boost::asio::ip::tcp::socket& s = c->socket; + std::string& d = c->data; + char* p = (d.empty() ? 0 : &d[0]); + + boost::asio::async_read( + s, + boost::asio::buffer(p, d.size()), + task_wrapped_with_connection(std::move(c), f) + ); +} + + +template +void async_read_dataat_least(connection_ptr&& c, const Functor& f, std::size_t at_least_bytes, std::size_t at_most = 4095) { + std::string& d = c->data; + d.resize(at_most); + char* p = (at_most == 0 ? 0 : &d[0]); + + boost::asio::ip::tcp::socket& s = c->socket; + + boost::asio::async_read( + s, + boost::asio::buffer(p, at_most), + boost::asio::transfer_at_least(at_least_bytes), + task_wrapped_with_connection(std::move(c), f) + ); +} + +namespace tp_network_client { + +class tasks_processor: public tp_timers::tasks_processor { + // ... + +public: + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network_cleint + + +#include +namespace tp_network { + +class tasks_processor: public tp_network_client::tasks_processor { + typedef boost::asio::ip::tcp::acceptor acceptor_t; + typedef boost::function on_accpet_func_t; + + struct tcp_listener { + acceptor_t acceptor_; + const on_accpet_func_t func_; + connection_ptr new_c_; + + template + tcp_listener( + boost::asio::io_service& io_service, + unsigned short port, + const Functor& task_unwrapped) + : acceptor_(io_service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::tcp::v4(), port + )) + , func_(task_unwrapped) + {} + }; + typedef std::unique_ptr listener_ptr; + + struct handle_accept { + listener_ptr listener; + + explicit handle_accept(listener_ptr&& l) + : listener(std::move(l)) + {} + + void operator()(const boost::system::error_code& error) { + task_wrapped_with_connection task(std::move(listener->new_c_), listener->func_); + if (error) { + std::cerr << error << '\n'; + } + + start_accepting_connection(std::move(listener)); + task(error, 0); + } + }; + + static void start_accepting_connection(listener_ptr&& listener) { + if (!listener->acceptor_.is_open()) { + return; + } + + listener->new_c_.reset( + new connection_with_data(listener->acceptor_.get_io_service()) + ); + + boost::asio::ip::tcp::socket& s = listener->new_c_->socket; + acceptor_t& a = listener->acceptor_; + a.async_accept( + s, + tasks_processor::handle_accept(std::move(listener)) + ); + } + +public: + template + static void add_listener(unsigned short port_num, const Functor& f) { + std::unique_ptr listener( + new tcp_listener(get_ios(), port_num, f) + ); + + start_accepting_connection(std::move(listener)); + } + + static connection_ptr create_connection(const char* addr, unsigned short port_num) { + connection_ptr c( new connection_with_data(get_ios()) ); + + c->socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::from_string(addr), + port_num + )); + + return c; + } +}; + +} // namespace tp_network + + +#include + +namespace tp_multithread { + +class tasks_processor: public tp_network::tasks_processor { +public: + // Default value will attempt to guess optimal count of threads. + static void start_multiple(std::size_t threads_count = 0) { + if (!threads_count) { + threads_count = (std::max)(static_cast( + boost::thread::hardware_concurrency()), 1 + ); + } + + // one thread is the current thread + -- threads_count; + + boost::asio::io_service& ios = get_ios(); + boost::thread_group tg; + for (std::size_t i = 0; i < threads_count; ++i) { + tg.create_thread([&ios]() { ios.run(); }); + } + + ios.run(); + tg.join_all(); + } +}; + +} // namespace tp_multithread + + + +#include +#include + +namespace tp_full { + +class tasks_processor: public tp_multithread::tasks_processor { +protected: + static boost::asio::signal_set& signals() { + static boost::asio::signal_set signals_(get_ios()); + return signals_; + } + + static boost::function& signal_handler() { + static boost::function users_signal_handler_; + return users_signal_handler_; + } + +private: + static void handle_signals( + const boost::system::error_code& error, + int signal_number) + { + signals().async_wait(&tasks_processor::handle_signals); + + if (error) { + std::cerr << "Error in signal handling: " << error << '\n'; + } else { + // If signals occures while there is no waiting handlers, + // signal notification is queued, so it won't be missed + // while we running users_signal_handler_ + boost::function h = signal_handler(); + detail::make_task_wrapped([h, signal_number]() { + h(signal_number); + })(); // make and run task_wrapped + } + + } +public: + + // This function is not threads safe! + // Must be called before all the `start()` calls + // Function can be called only once + template + static void register_signals_handler( + const Func& f, + const std::vector& signals_to_wait) + { + + // Making shure that this is the first call + assert(!signal_handler()); + + signal_handler() = f; + boost::asio::signal_set& sigs = signals(); + + std::for_each( + signals_to_wait.begin(), + signals_to_wait.end(), + [&sigs](int signal) { sigs.add(signal); } + ); + + signals().async_wait(&tasks_processor::handle_signals); + } +}; + +} // namespace tp_full + + +using namespace tp_full; + +void accept_3_signals_and_stop(int signal) { + static int signals_count = 0; + assert(signal == SIGINT); + ++ signals_count; + std::cout << "Captured " << signals_count << " SIGINT\n"; + if (signals_count == 3) { + tasks_processor::stop(); + } +} + + +int main () { + tasks_processor::register_signals_handler( + &accept_3_signals_and_stop, + std::vector(1, SIGINT) // vector containing 1 element + ); + + tasks_processor::start(); +} diff --git a/Chapter06/flat/Readme.md b/Chapter06/flat/Readme.md new file mode 100644 index 00000000..0f72e08b --- /dev/null +++ b/Chapter06/flat/Readme.md @@ -0,0 +1,6 @@ +This directory contains preprocessed code from the ../Chapter06 folder: +* All the headers were copyied into the main.cpp +* Include guards were removed +* Project files updated accordingly + +Files in this folder are used by online compiler (it can not deal with foreign includes). diff --git a/Chapter06/flat/flat.pro b/Chapter06/flat/flat.pro new file mode 100644 index 00000000..f7df4bae --- /dev/null +++ b/Chapter06/flat/flat.pro @@ -0,0 +1,12 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + 01_tasks_processor_base \ + 02_tasks_processor_timers \ + 04_tasks_processor_network_accept \ + 05_tasks_processor_multithread \ + 07_nonblocking_barrier \ + 08_exception_ptr \ + 09_tasks_processor_signals + + diff --git a/Chapter06/flat/flatten.py b/Chapter06/flat/flatten.py new file mode 100644 index 00000000..35d16fa1 --- /dev/null +++ b/Chapter06/flat/flatten.py @@ -0,0 +1,63 @@ +import os +import sys +import signal +import subprocess +import re +import shutil + +class flattener: + ''' ****************************************** Private functions ********************************************** ''' + @staticmethod + def _process_source(out, path): + with open(path, 'r') as f: + for line in f: + m = re.findall(r'#include.*"(.*?)"', line) + if m: + d = os.path.dirname(path) + flattener._process_source(out, os.path.join(d, m[0])) + elif 'BOOK_' not in line: + out.write(line) + + @staticmethod + def _flat_source(path): + flat_name = os.path.join( + os.path.dirname(path).replace('../', ''), + "main.cpp" + ) + try: + with open(flat_name, 'w+') as out: + flattener._process_source(out, path) + if 'tasks_processor_network_accept' in flat_name: + with open('../03_tasks_processor_network_client/client.cpp', 'r') as f: + for line in f: + m = re.findall(r'#include.*"(.*?)"', line) + if not m and 'using namespace' not in line: + out.write(line) + except: + pass + + @staticmethod + def _is_source(path): + return os.path.isfile(path) and '.cpp' in path and 'flat' not in path + + ''' ****************************************** Public functions *********************************************** ''' + @staticmethod + def make_flat(): + print "\nStarting flattening..." + + for folder, _, files in os.walk('..'): + if 'flat' in folder: + continue + + for f in files: + path = os.path.join(folder, f) + if flattener._is_source(path): + flattener._flat_source(path) + + print "\n*** SUCESS ***" + + +if __name__ == "__main__": + flattener.make_flat() + + diff --git a/Readme.md b/Readme.md index 1e57e4ba..0640db76 100644 --- a/Readme.md +++ b/Readme.md @@ -4,6 +4,11 @@ This repository contains all the code examples from the **[Boost C++ Application [Compile and Run Examples Online](http://apolukhin.github.io/Boost-Cookbook-4880OS/). +### Testing +Second edition: [![Build Status](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS.svg?branch=second_edition)](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS) [![Build status](https://ci.appveyor.com/api/projects/status/github/apolukhin/boost-cookbook-4880os?branch=second_edition&svg=true)](https://ci.appveyor.com/project/apolukhin/boost-cookbook-4880os/branch/second_edition) [![Coverage Status](https://coveralls.io/repos/github/apolukhin/Boost-Cookbook-4880OS/badge.svg?branch=second_edition)](https://coveralls.io/github/apolukhin/Boost-Cookbook-4880OS?branch=second_edition) [![codecov.io](https://codecov.io/github/apolukhin/Boost-Cookbook-4880OS/coverage.svg?branch=second_edition)](https://codecov.io/github/apolukhin/Boost-Cookbook-4880OS?branch=second_edition) + +First edition: [![Build Status](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS.svg?branch=first_edition)](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS) [![Coverage Status](https://coveralls.io/repos/github/apolukhin/Boost-Cookbook-4880OS/badge.svg?branch=first_edition)](https://coveralls.io/github/apolukhin/Boost-Cookbook-4880OS?branch=first_edition) + ### Content This repository contatins project files for QtCreator IDE. `BoostBook.pro` - is the main project file. See config.txt file for setupping platform specific flags. @@ -37,30 +42,30 @@ require searching all around the chapter for an answer 'In what namespace is this class defined?'. -### Thanks -Thanks to Heather Gopsill from Packt Publishing for giving a permission to make sources publicly available. -### Testing -[![Build Status](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS.svg?branch=master)](https://travis-ci.org/apolukhin/Boost-Cookbook-4880OS) [![Coverage Status](https://coveralls.io/repos/apolukhin/Boost-Cookbook-4880OS/badge.svg)](https://coveralls.io/r/apolukhin/Boost-Cookbook-4880OS) +### Thanks +Thanks to Heather Gopsill from Packt Publishing for giving a permission to make sources publicly available. +Thanks to Nitin Dasan from Packt Publishing for getting all the necessary approvals for making sources publicly available for the second edition of the book. ### Notes for book update * Chapter 10 "Detecting RTTI support" - add Boost.TypeIndex example AND Sync code * Chapter07 Note about boost::string_ref(string&&) and boost::string_view -* Boost will have an unique_ptr in 1.58 * How about describing boost::future? * Coroutine interface changed in Boost 1.56 -* LexicalCast now has a try_lexical_convert method * Filesystem is accepted into the Standard * RCU example using atomics? -* add *_pointer_cast examples? * sync code and book * Fix introduction in "Chapter09. Getting the benefits of single-linked list and memory pool" * Boost.DLL examples * flat containers were proposed for C++17 -* describe in depth changes from 135a24926a1d084e76f8f527deeee6236274e496 +* Update this README.md with a link to second edition of the book Done: * Optional and Variant now understand rvalue references * add a note to the book about source code availability at github * Variant is proposed for C++17. Highlight the differences. +* Boost will have an unique_ptr in 1.58 +* LexicalCast now has a try_lexical_convert method +* add *_pointer_cast examples? +* describe in depth changes from 135a24926a1d084e76f8f527deeee6236274e496