/*
** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
#define lopcodes_c
#define LUA_CORE
#include "lprefix.h"
#include <stddef.h>
#include "lopcodes.h"
/* ORDER OP */
LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888 } /* Comment */
.highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */
.highlight .k { color: #080; font-weight: bold } /* Keyword */
.highlight .ch { color: #888 } /* Comment.Hashbang */
.highlight .cm { color: #888 } /* Comment.Multiline */
.highlight .cp { color: #C00; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888 } /* Comment.Single */
.highlight .cs { color: #C00; font-weight: bold; background-color: #FFF0F0 } /* Comment.Special */
.highlight .gd { color: #000; background-color: #FDD } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #A00 } /* Generic.Error */
.highlight .gh { color: #333 } /* Generic.Heading */
.highlight .gi { color: #000; background-color: #DFD } /* Generic.Inserted */
.highlight .go { color: #888 } /* Generic.Output */
.highlight .gp { color: #555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666 } /* Generic.Subheading */
.highlight .gt { color: #A00 } /* Generic.Traceback */
.highlight .kc { color: #080; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #080; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #080; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #080 } /* Keyword.Pseudo */
.highlight .kr { color: #080; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #00D; font-weight: bold } /* Literal.Number */
.highlight .s { color: #D20; background-color: #FFF0F0 } /* Literal.String */
.highlight .na { color: #369 } /* Name.Attribute */
.highlight .nb { color: #038 } /* Name.Builtin */
.highlight .nc { color: #B06; font-weight: bold } /* Name.Class */
.highlight .no { color: #036; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555 } /* Name.Decorator */
.highlight .ne { color: #B06; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #06B; font-weight: bold } /* Name.Function */
.highlight .nl { color: #369; font-style: italic } /* Name.Label */
.highlight .nn { color: #B06; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #369; font-weight: bold } /* Name.Property */
.highlight .nt { color: #B06; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #369 } /* Name.Variable */
.highlight .ow { color: #080 } /* Operator.Word */
.highlight .w { color: #BBB } /* Text.Whitespace */
.highlight .mb { color: #00D; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #00D; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #00D; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #00D; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #00D; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #D20; background-color: #FFF0F0 } /* Literal.String.Affix */
.highlight .sb { color: #D20; background-color: #FFF0F0 } /* Literal.String.Backtick */
.highlight .sc { color: #D20; background-color: #FFF0F0 } /* Literal.String.Char */
.highlight .dl { color: #D20; background-color: #FFF0F0 } /* Literal.String.Delimiter */
.highlight .sd { color: #D20; background-color: #FFF0F0 } /* Literal.String.Doc */
.highlight .s2 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Double */
.highlight .se { color: #04D; background-color: #FFF0F0 } /* Literal.String.Escape */
.highlight .sh { color: #D20; background-color: #FFF0F0 } /* Literal.String.Heredoc */
.highlight .si { color: #33B; background-color: #FFF0F0 } /* Literal.String.Interpol */
.highlight .sx { color: #2B2; background-color: #F0FFF0 } /* Literal.String.Other */
.highlight .sr { color: #080; background-color: #FFF0FF } /* Literal.String.Regex */
.highlight .s1 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Single */
.highlight .ss { color: #A60; background-color: #FFF0F0 } /* Literal.String.Symbol */
.highlight .bp { color: #038 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06B; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #369 } /* Name.Variable.Class */
.highlight .vg { color: #D70 } /* Name.Variable.Global */
.highlight .vi { color: #33B } /* Name.Variable.Instance */
.highlight .vm { color: #369 } /* Name.Variable.Magic */
.highlight .il { color: #00D; font-weight: bold } /* Literal.Number.Integer.Long *///
// composed_5.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 <asio/deferred.hpp>
#include <asio/io_context.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/use_future.hpp>
#include <asio/write.hpp>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
using asio::ip::tcp;
// NOTE: This example requires the new asio::async_initiate function. For
// an example that works with the Networking TS style of completion tokens,
// please see an older version of asio.
//------------------------------------------------------------------------------
// This composed operation automatically serialises a message, using its I/O
// streams insertion operator, before sending it on the socket. To do this, it
// must allocate a buffer for the encoded message and ensure this buffer's
// validity until the underlying async_write operation completes.
// In addition to determining the mechanism by which an asynchronous operation
// delivers its result, a completion token also determines the time when the
// operation commences. For example, when the completion token is a simple
// callback the operation commences before the initiating function returns.
// However, if the completion token's delivery mechanism uses a future, we
// might instead want to defer initiation of the operation until the returned
// future object is waited upon.
//
// To enable this, when implementing an asynchronous operation we must package
// the initiation step as a function object.
struct async_write_message_initiation
{
// The initiation function object's call operator is passed the concrete
// completion handler produced by the completion token. This completion
// handler matches the asynchronous operation's completion handler signature,
// which in this example is:
//
// void(std::error_code error)
//
// The initiation function object also receives any additional arguments
// required to start the operation. (Note: We could have instead passed these
// arguments as members in the initiaton function object. However, we should
// prefer to propagate them as function call arguments as this allows the
// completion token to optimise how they are passed. For example, a lazy
// future which defers initiation would need to make a decay-copy of the
// arguments, but when using a simple callback the arguments can be trivially
// forwarded straight through.)
template <typename CompletionHandler>
void operator()(CompletionHandler&& completion_handler,
tcp::socket& socket, std::unique_ptr<std::string> encoded_message) const
{
// In this example, the composed operation's intermediate completion
// handler is implemented as a hand-crafted function object, rather than
// using a lambda or std::bind.
struct intermediate_completion_handler
{
// The intermediate completion handler holds a reference to the socket so
// that it can obtain the I/O executor (see get_executor below).
tcp::socket& socket_;
// The allocated buffer for the encoded message. The std::unique_ptr
// smart pointer is move-only, and as a consequence our intermediate
// completion handler is also move-only.
std::unique_ptr<std::string> encoded_message_;
// The user-supplied completion handler.
typename std::decay<CompletionHandler>::type handler_;
// The function call operator matches the completion signature of the
// async_write operation.
void operator()(const std::error_code& error, std::size_t /*n*/)
{
// Deallocate the encoded message before calling the user-supplied
// completion handler.
encoded_message_.reset();
// Call the user-supplied handler with the result of the operation.
// The arguments must match the completion signature of our composed
// operation.
handler_(error);
}
// It is essential to the correctness of our composed operation that we
// preserve the executor of the user-supplied completion handler. With a
// hand-crafted function object we can do this by defining a nested type
// executor_type and member function get_executor. These obtain the
// completion handler's associated executor, and default to the I/O
// executor - in this case the executor of the socket - if the completion
// handler does not have its own.
using executor_type = asio::associated_executor_t<
typename std::decay<CompletionHandler>::type,
tcp::socket::executor_type>;
executor_type get_executor() const noexcept
{
return asio::get_associated_executor(
handler_, socket_.get_executor());
}
// Although not necessary for correctness, we may also preserve the
// allocator of the user-supplied completion handler. This is achieved by
// defining a nested type allocator_type and member function
// get_allocator. These obtain the completion handler's associated
// allocator, and default to std::allocator<void> if the completion
// handler does not have its own.
using allocator_type = asio::associated_allocator_t<
typename std::decay<CompletionHandler>::type,
std::allocator<void>>;
allocator_type get_allocator() const noexcept
{
return asio::get_associated_allocator(
handler_, std::allocator<void>{});
}
};
// Initiate the underlying async_write operation using our intermediate
// completion handler.
auto encoded_message_buffer = asio::buffer(*encoded_message);
asio::async_write(socket, encoded_message_buffer,
intermediate_completion_handler{socket, std::move(encoded_message),
std::forward<CompletionHandler>(completion_handler)});
}
};
template <typename T, typename CompletionToken>
auto async_write_message(tcp::socket& socket,
const T& message, 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<void>. When
// the completion token is asio::deferred, the return type differs for each
// asynchronous operation.
//
// In C++11 we deduce the type from the call to asio::async_initiate.
-> decltype(
asio::async_initiate<
CompletionToken, void(std::error_code)>(
async_write_message_initiation(), token,
std::ref(socket), std::declval<std::unique_ptr<std::string>>()))
{
// Encode the message and copy it into an allocated buffer. The buffer will
// be maintained for the lifetime of the asynchronous operation.
std::ostringstream os;
os << message;
std::unique_ptr<std::string> encoded_message(new std::string(os.str()));
// The asio::async_initiate function takes:
//
// - our initiation function object,
// - the completion token,
// - the completion handler signature, and
// - any additional arguments we need to initiate the operation.
//
// It then asks the completion token to create a completion handler (i.e. a
// callback) with the specified signature, and invoke the initiation function
// object with this completion handler as well as the additional arguments.
// The return value of async_initiate is the result of our operation's
// initiating function.
//
// Note that we wrap non-const reference arguments in std::reference_wrapper
// to prevent incorrect decay-copies of these objects.
return asio::async_initiate<
CompletionToken, void(std::error_code)>(
async_write_message_initiation(), token,
std::ref(socket), std::move(encoded_message));
}
//------------------------------------------------------------------------------
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_message(socket, 123456,
[](const std::error_code& error)
{
if (!error)
{
std::cout << "Message 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 and its arguments to return a function object, which may then be
// used to launch the asynchronous operation.
auto op = async_write_message(socket,
std::string("abcdef"), asio::deferred);
// Launch the operation using a lambda as a callback.
std::move(op)(
[](const std::error_code& error)
{
if (!error)
{
std::cout << "Message 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<void> f = async_write_message(
socket, 654.321, asio::use_future);
io_context.run();
try
{
// Get the result of the operation.
f.get();
std::cout << "Message sent\n";
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
}
//------------------------------------------------------------------------------
int main()
{
test_callback();
test_deferred();
test_future();
}