// // composed_8.cpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2024 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include using asio::ip::tcp; // NOTE: This example requires the new asio::async_compose function. For // an example that works with the Networking TS style of completion tokens, // please see an older version of asio. //------------------------------------------------------------------------------ // This composed operation shows composition of multiple underlying operations, // using asio's stackless coroutines support to express the flow of control. It // automatically serialises a message, using its I/O streams insertion // operator, before sending it N times on the socket. To do this, it must // allocate a buffer for the encoded message and ensure this buffer's validity // until all underlying async_write operation complete. A one second delay is // inserted prior to each write operation, using a steady_timer. #include template auto async_write_messages(tcp::socket& socket, const T& message, std::size_t repeat_count, CompletionToken&& token) // The return type of the initiating function is deduced from the combination // of: // // - the CompletionToken type, // - the completion handler signature, and // - the asynchronous operation's initiation function object. // // When the completion token is a simple callback, the return type is always // void. In this example, when the completion token is asio::yield_context // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the // completion token is asio::use_future it would be std::future. When // the completion token is asio::deferred, the return type differs for each // asynchronous operation. // // In C++14 we can omit the return type as it is automatically deduced from // the return type of asio::async_compose. { // Encode the message and copy it into an allocated buffer. The buffer will // be maintained for the lifetime of the composed asynchronous operation. std::ostringstream os; os << message; std::unique_ptr encoded_message(new std::string(os.str())); // Create a steady_timer to be used for the delay between messages. std::unique_ptr delay_timer( new asio::steady_timer(socket.get_executor())); // The asio::async_compose function takes: // // - our asynchronous operation implementation, // - the completion token, // - the completion handler signature, and // - any I/O objects (or executors) used by the operation // // It then wraps our implementation, which is implemented here as a stackless // coroutine in a lambda, in an intermediate completion handler that meets the // requirements of a conforming asynchronous operation. This includes // tracking outstanding work against the I/O executors associated with the // operation (in this example, this is the socket's executor). // // The first argument to our lambda is a reference to the enclosing // intermediate completion handler. This intermediate completion handler is // provided for us by the asio::async_compose function, and takes care // of all the details required to implement a conforming asynchronous // operation. When calling an underlying asynchronous operation, we pass it // this enclosing intermediate completion handler as the completion token. // // All arguments to our lambda after the first must be defaulted to allow the // state machine to be started, as well as to allow the completion handler to // match the completion signature of both the async_write and // steady_timer::async_wait operations. return asio::async_compose< CompletionToken, void(std::error_code)>( [ // The implementation holds a reference to the socket as it is used for // multiple async_write operations. &socket, // The allocated buffer for the encoded message. The std::unique_ptr // smart pointer is move-only, and as a consequence our lambda // implementation is also move-only. encoded_message = std::move(encoded_message), // The repeat count remaining. repeat_count, // A steady timer used for introducing a delay. delay_timer = std::move(delay_timer), // The coroutine state. coro = asio::coroutine() ] ( auto& self, const std::error_code& error = {}, std::size_t = 0 ) mutable { reenter (coro) { while (repeat_count > 0) { --repeat_count; delay_timer->expires_after(std::chrono::seconds(1)); yield delay_timer->async_wait(std::move(self)); if (error) break; yield asio::async_write(socket, asio::buffer(*encoded_message), std::move(self)); if (error) break; } // Deallocate the encoded message and delay timer before calling the // user-supplied completion handler. encoded_message.reset(); delay_timer.reset(); // Call the user-supplied handler with the result of the operation. self.complete(error); } }, token, socket); } #include //------------------------------------------------------------------------------ void test_callback() { asio::io_context io_context; tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); tcp::socket socket = acceptor.accept(); // Test our asynchronous operation using a lambda as a callback. async_write_messages(socket, "Testing callback\r\n", 5, [](const std::error_code& error) { if (!error) { std::cout << "Messages sent\n"; } else { std::cout << "Error: " << error.message() << "\n"; } }); io_context.run(); } //------------------------------------------------------------------------------ void test_deferred() { asio::io_context io_context; tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); tcp::socket socket = acceptor.accept(); // Test our asynchronous operation using the deferred completion token. This // token causes the operation's initiating function to package up the // operation with its arguments to return a function object, which may then be // used to launch the asynchronous operation. auto op = async_write_messages(socket, "Testing deferred\r\n", 5, asio::deferred); // Launch the operation using a lambda as a callback. std::move(op)( [](const std::error_code& error) { if (!error) { std::cout << "Messages sent\n"; } else { std::cout << "Error: " << error.message() << "\n"; } }); io_context.run(); } //------------------------------------------------------------------------------ void test_future() { asio::io_context io_context; tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); tcp::socket socket = acceptor.accept(); // Test our asynchronous operation using the use_future completion token. // This token causes the operation's initiating function to return a future, // which may be used to synchronously wait for the result of the operation. std::future f = async_write_messages( socket, "Testing future\r\n", 5, asio::use_future); io_context.run(); try { // Get the result of the operation. f.get(); std::cout << "Messages sent\n"; } catch (const std::exception& e) { std::cout << "Error: " << e.what() << "\n"; } } //------------------------------------------------------------------------------ int main() { test_callback(); test_deferred(); test_future(); } { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#!/usr/bin/python
##
## license:BSD-3-Clause
## copyright-holders:Vas Crabb

import io
import os
import os.path
import re
import sys


def write_output(text):
    try:
        dst.write(text)
    except IOError:
        if dstfile is not None:
            sys.stderr.write('Error writing to output file \'%s\'\n' % dstfile)
            dst.close()
            os.remove(dstfile)
        else:
            sys.stderr.write('Error writing to output\n')
        sys.exit(3)


if __name__ == '__main__':
    if (len(sys.argv) > 4) or (len(sys.argv) < 2):
        print('Usage:')
        print('  file2lines <source.txt> [<output.h> [<varname>]]')
        sys.exit(0 if len(sys.argv) <= 1 else 1)

    srcfile = sys.argv[1]
    dstfile = sys.argv[2] if len(sys.argv) >= 3 else None
    if len(sys.argv) >= 4:
        varname = sys.argv[3]
    else:
        varname = os.path.basename(srcfile)
        base, ext = os.path.splitext(varname)
        if ext.lower() == '.txt':
            varname = base
        varname = 'lines_' + re.sub('[^0-9A-Za-z_]', '_', varname)

    dst = None
    try:
        with io.open(srcfile, 'r', encoding='utf-8') as src:
            if dstfile is not None:
                try:
                    dst = io.open(dstfile, 'w', encoding='utf-8')
                except IOError:
                    sys.stderr.write('Unable to open output file \'%s\'\n' % dstfile)
                    sys.exit(3)
            else:
                dst = sys.stdout
            write_output(u'char const *const %s[] = {\n' % varname)
            for line in src:
                if line[-1] == u'\n':
                    line = line[:-1]
                write_output(u'\t\t"')
                i = 0
                while i < len(line):
                    for j in range(i, len(line) + 1):
                        if j < len(line):
                            ch = line[j]
                            if (ch < u' ') or (ch > u'~') or (ch in u'\"\\'):
                                break
                    if j > i:
                        write_output(line[i:j])
                    if j < len(line):
                        ch = line[j]
                        if ch == u'\a':
                            write_output(u'\\a')
                        elif ch == u'\f':
                            write_output(u'\\f')
                        elif ch == u'\t':
                            write_output(u'\\t')
                        elif ch == u'\v':
                            write_output(u'\\v')
                        elif ch in u'\"\\':
                            write_output(u'\\' + ch)
                        else:
                            ch = ord(ch)
                            if ch < 0x20:
                                write_output(u'\\{0:03o}'.format(ch))
                            elif ch < 0x10000:
                                write_output(u'\\u{0:04X}'.format(ch))
                            else:
                                write_output(u'\\U{0:08X}'.format(ch))
                    i = j + 1
                write_output(u'",\n')
            write_output(u'\t\tnullptr };\n')
    except IOError:
        sys.stderr.write('Error reading input file \'%s\'\n' % srcfile)
        if (dstfile is not None) and (dst is not None):
            dst.close()
            os.remove(dstfile)
        sys.exit(2)