commit a1f3d3a1b80f90935a5c6ea1837564b6d7f59d3b Author: Deukhoofd Date: Tue Sep 28 18:13:22 2021 +0200 Initial commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..965124f --- /dev/null +++ b/.clang-format @@ -0,0 +1,123 @@ +# ClangFormatConfigureSource: 'LLVM' +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Merge +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 1 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION + - Assert + - AssertNotNull +TabWidth: 8 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..884002b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,11 @@ +Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*, +bugprone-*,modernize-*,-modernize-use-trailing-return-type' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.PrivateMemberCase + value: camelBack + - key: readability-identifier-naming.PrivateMemberPrefix + value: '_' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b550f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/cmake-build-debug/ +/cmake-build-debug-windows/ +/cmake-build-debug-coverage/ +/cmake-build-release/ +/build-release-windows/ +/.idea/ +/docs/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e733640 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extern/websocketpp"] + path = extern/websocketpp + url = https://github.com/zaphoyd/websocketpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc5f567 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.20) +project(AngelscriptDebugger) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +option(WINDOWS "Whether the build target is Windows or not." OFF) +option(SHARED "Whether we should build a shared library, instead of a static one." ON) +option(STATICC "Whether gcc and stdc++ should be linked statically to the library." OFF) + +include(CMakeLists.txt.angelscript.in) +include_angelscript() + + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_compile_options(-fconcepts) +endif () + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_link_options(-fuse-ld=lld) +endif () + +if (WINDOWS) + SET(CMAKE_SYSTEM_NAME Windows) + ADD_DEFINITIONS(-D WINDOWS=1) +endif (WINDOWS) + +message(STATUS "Using: +\t C ${CMAKE_C_COMPILER} +\t C++ ${CMAKE_CXX_COMPILER} +\t CXX ABI ${CMAKE_CXX_COMPILER_ABI} +\t C++ Version ${CMAKE_CXX_STANDARD}") + +if (CMAKE_BUILD_TYPE MATCHES Release AND NOT WINDOWS) + # Include debug symbols in all linux builds + message("Including debug symbols") + add_compile_options(-g -gline-tables-only) +endif () + +# Set whether we want a static or shared library. +set(LIBTYPE STATIC) +if (SHARED) + set(LIBTYPE SHARED) +endif (SHARED) + +file(GLOB_RECURSE SRC_FILES "src/*.cpp" "src/*.hpp") +add_library(AngelscriptDebugger ${LIBTYPE} ${SRC_FILES}) +target_compile_options(AngelscriptDebugger PRIVATE -Wall -Wextra -Werror) +target_include_directories(AngelscriptDebugger PRIVATE extern/asio-1.18.2/include) + +SET(_LINKS angelscript) +if (WINDOWS) + MESSAGE(WARNING, "Using Windows Build.") + # Add a definition for the compiler, so we can use it in C++ as well. + ADD_DEFINITIONS(-D WINDOWS=1) + # -m64: Build a 64 bit library + add_compile_options(-m64) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-allow-multiple-definition") + if (SHARED) + set_target_properties(pkmnLib PROPERTIES SUFFIX ".dll") + endif(SHARED) +endif (WINDOWS) + +if (STATICC) + set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + message(STATUS "Linking C library statically") + set(_LINKS ${_LINKS} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lm -lstdc++ -lpthread -Wl,-Bdynamic) + SET(_TESTLINKS ${_TESTLINKS} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic) +else() + SET(_LINKS ${_LINKS} -Wl,--whole-archive -lpthread -Wl,--no-whole-archive) +endif() + +target_link_libraries(AngelscriptDebugger PUBLIC ${_LINKS}) + +file(GLOB_RECURSE RUNNER_SRC_FILES "TestRunner/*.cpp" "TestRunner/*.hpp") +add_executable(AngelscriptDebuggerRunner ${RUNNER_SRC_FILES}) +target_include_directories(AngelscriptDebuggerRunner PRIVATE extern/asio-1.18.2/include) +target_link_libraries(AngelscriptDebuggerRunner AngelscriptDebugger) \ No newline at end of file diff --git a/CMakeLists.txt.angelscript.in b/CMakeLists.txt.angelscript.in new file mode 100644 index 0000000..df3877e --- /dev/null +++ b/CMakeLists.txt.angelscript.in @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(AngelscriptDebugger NONE) + +include(ExternalProject) + +ExternalProject_Add(AngelscriptProj + GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/Angelscript.git + GIT_TAG master + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/Angelscript" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + +function(include_angelscript) + configure_file(CMakeLists.txt.angelscript.in Angelscript/download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Angelscript/download) + if (result) + message(FATAL_ERROR "CMake step for angelscript failed: ${result}") + endif () + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Angelscript/download) + if (result) + message(FATAL_ERROR "Build step for angelscript failed: ${result}") + endif () + + SET(BUILD_SHARED_LIBS ${SHARED}) + SET(LINK_STD_STATICALLY ${STATICC}) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON) + if (WINDOWS) + SET(MSVC 1) + endif() + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/Angelscript/src/AngelscriptProj/angelscript/projects/cmake + ${CMAKE_CURRENT_BINARY_DIR}/Angelscript/bin + EXCLUDE_FROM_ALL) + + if (WINDOWS) + set_target_properties(angelscript PROPERTIES SUFFIX ".dll") + endif (WINDOWS) + + execute_process(COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/Angelscript/include) + include_directories(SYSTEM ${CMAKE_CURRENT_BINARY_DIR}/Angelscript/src/AngelscriptProj/angelscript/include) +endfunction() \ No newline at end of file diff --git a/Heady b/Heady new file mode 100755 index 0000000..42266bd Binary files /dev/null and b/Heady differ diff --git a/TestRunner/Runner.cpp b/TestRunner/Runner.cpp new file mode 100644 index 0000000..0a44425 --- /dev/null +++ b/TestRunner/Runner.cpp @@ -0,0 +1,94 @@ +#include +#include "../src/AngelscriptDebugger.hpp" +#include "angelscript_addons/scriptarray/scriptarray.h" +#include "angelscript_addons/scriptbuilder/scriptbuilder.h" +#include "angelscript_addons/scripthelper/scripthelper.h" +#include "angelscript_addons/scriptstdstring/scriptstdstring.h" + +static void print(const std::string& s) { std::cout << s << std::endl; } + +void MessageCallback(const asSMessageInfo* msg, void* param) { + const char* type = "ERR "; + if (msg->type == asMSGTYPE_WARNING) + type = "WARN"; + else if (msg->type == asMSGTYPE_INFORMATION) + type = "INFO"; + printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); +} + +int main() { + AngelscriptDebugger debugger; + debugger.Run(8684); + + std::cout << "Waiting for debugger to attach." << std::endl; + while (!debugger.HasDebuggerAttached()) { + usleep(1000); + } + std::cout << "Debugger attached." << std::endl; + + + asIScriptEngine* engine = asCreateScriptEngine(); + engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); + RegisterStdString(engine); + RegisterScriptArray(engine, true); + RegisterExceptionRoutines(engine); + assert(engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL) >= 0); + + CScriptBuilder builder; + assert(builder.StartNewModule(engine, "TestModule") >= 0); + assert(builder.AddSectionFromMemory("TestScript", R"( +class TestClass { + int TestField = 45435; + TestClass@ RecursiveField; + + TestClass(){ + @RecursiveField = this; + } + + void main(int a, int b, string d){ + int c = a + b; + int[] arr = {20, 40, 80, 160}; + print(formatInt(c)); + print(d); + throw("Error message"); + } +})") >= 0); + auto buildResult = builder.BuildModule(); + if (buildResult < 0) { + std::cout << "Failed building module with error code: " << buildResult << std::endl; + + return 1; + } + + asIScriptModule* mod = engine->GetModule("TestModule"); + + asITypeInfo* type = mod->GetTypeInfoByDecl("TestClass"); + asIScriptFunction* factory = type->GetFactoryByDecl("TestClass @TestClass()"); + + asIScriptContext* ctx = engine->CreateContext(); + debugger.RegisterContext(ctx); + + ctx->Prepare(factory); + ctx->Execute(); + asIScriptObject* obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue(); + obj->AddRef(); + + asIScriptFunction* func = type->GetMethodByName("main"); + + assert(ctx->Prepare(func) == asSUCCESS); + ctx->SetObject(obj); + ctx->SetArgDWord(0, 100); + ctx->SetArgDWord(1, 684); + std::string s = "foobar"; + ctx->SetArgObject(2, &s); + ctx->Execute(); + while (ctx->GetState() != asEXECUTION_FINISHED && ctx->GetState() != asEXECUTION_EXCEPTION && + ctx->GetState() != asEXECUTION_ABORTED && ctx->GetState() != asEXECUTION_ERROR) { + usleep(1000); + } + + ctx->Release(); + obj->Release(); + engine->ShutDownAndRelease(); + debugger.Stop(); +} \ No newline at end of file diff --git a/TestRunner/angelscript_addons/scriptarray/scriptarray.cpp b/TestRunner/angelscript_addons/scriptarray/scriptarray.cpp new file mode 100644 index 0000000..58512f3 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptarray/scriptarray.cpp @@ -0,0 +1,2186 @@ +#include +#include +#include +#include +#include // sprintf +#include +#include // std::sort + +#include "scriptarray.h" + +using namespace std; + +BEGIN_AS_NAMESPACE + +// This macro is used to avoid warnings about unused variables. +// Usually where the variables are only used in debug mode. +#define UNUSED_VAR(x) (void)(x) + +// Set the default memory routines +// Use the angelscript engine's memory routines by default +static asALLOCFUNC_t userAlloc = asAllocMem; +static asFREEFUNC_t userFree = asFreeMem; + +// Allows the application to set which memory routines should be used by the array object +void CScriptArray::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) +{ + userAlloc = allocFunc; + userFree = freeFunc; +} + +static void RegisterScriptArray_Native(asIScriptEngine *engine); +static void RegisterScriptArray_Generic(asIScriptEngine *engine); + +struct SArrayBuffer +{ + asDWORD maxElements; + asDWORD numElements; + asBYTE data[1]; +}; + +struct SArrayCache +{ + asIScriptFunction *cmpFunc; + asIScriptFunction *eqFunc; + int cmpFuncReturnCode; // To allow better error message in case of multiple matches + int eqFuncReturnCode; +}; + +// We just define a number here that we assume nobody else is using for +// object type user data. The add-ons have reserved the numbers 1000 +// through 1999 for this purpose, so we should be fine. +const asPWORD ARRAY_CACHE = 1000; + +static void CleanupTypeInfoArrayCache(asITypeInfo *type) +{ + SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); + if( cache ) + { + cache->~SArrayCache(); + userFree(cache); + } +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, ti); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(ti, initList); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti) +{ + return CScriptArray::Create(ti, asUINT(0)); +} + +// This optional callback is called when the template type is first used by the compiler. +// It allows the application to validate if the template can be instantiated for the requested +// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect +// allow the callback to tell the engine if the template instance type shouldn't be garbage collected, +// i.e. no asOBJ_GC flag. +static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) +{ + // Make sure the subtype can be instantiated with a default factory/constructor, + // otherwise we won't be able to instantiate the elements. + int typeId = ti->GetSubTypeId(); + if( typeId == asTYPEID_VOID ) + return false; + if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) + { + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) + { + // Verify that there is a default constructor + bool found = false; + for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ ) + { + asEBehaviours beh; + asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh); + if( beh != asBEHAVE_CONSTRUCT ) continue; + + if( func->GetParamCount() == 0 ) + { + // Found the default constructor + found = true; + break; + } + } + + if( !found ) + { + // There is no default constructor + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); + return false; + } + } + else if( (flags & asOBJ_REF) ) + { + bool found = false; + + // If value assignment for ref type has been disabled then the array + // can be created if the type has a default factory function + if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + { + // Verify that there is a default factory + for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) + { + asIScriptFunction *func = subtype->GetFactoryByIndex(n); + if( func->GetParamCount() == 0 ) + { + // Found the default factory + found = true; + break; + } + } + } + + if( !found ) + { + // No default factory + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); + return false; + } + } + + // If the object type is not garbage collected then the array also doesn't need to be + if( !(flags & asOBJ_GC) ) + dontGarbageCollect = true; + } + else if( !(typeId & asTYPEID_OBJHANDLE) ) + { + // Arrays with primitives cannot form circular references, + // thus there is no need to garbage collect them + dontGarbageCollect = true; + } + else + { + assert( typeId & asTYPEID_OBJHANDLE ); + + // It is not necessary to set the array as garbage collected for all handle types. + // If it is possible to determine that the handle cannot refer to an object type + // that can potentially form a circular reference with the array then it is not + // necessary to make the array garbage collected. + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( !(flags & asOBJ_GC) ) + { + if( (flags & asOBJ_SCRIPT_OBJECT) ) + { + // Even if a script class is by itself not garbage collected, it is possible + // that classes that derive from it may be, so it is not possible to know + // that no circular reference can occur. + if( (flags & asOBJ_NOINHERIT) ) + { + // A script class declared as final cannot be inherited from, thus + // we can be certain that the object cannot be garbage collected. + dontGarbageCollect = true; + } + } + else + { + // For application registered classes we assume the application knows + // what it is doing and don't mark the array as garbage collected unless + // the type is also garbage collected. + dontGarbageCollect = true; + } + } + } + + // The type is ok + return true; +} + +// Registers the template array type +void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0 ) + RegisterScriptArray_Native(engine); + else + RegisterScriptArray_Generic(engine); + + if( defaultArray ) + { + int r = engine->RegisterDefaultArrayType("array"); assert( r >= 0 ); + UNUSED_VAR(r); + } +} + +static void RegisterScriptArray_Native(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the object type user data clean up + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + + // Register the array type as a template + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + + // Register a callback for validating the subtype before it is used + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + + // Templates receive the object type as the first parameter. To the script writer this is hidden + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + + // Register the factory that will be used for initialization lists + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + + // The memory management methods + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); + + // The index operator returns the template subtype + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + + // The assignment operator + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); + + // Other methods + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); + // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? + // TODO: Register as size() for consistency with other types +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); + // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int find(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + + // Sort with callback for comparison + r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); + +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + // Register virtual properties + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); +#endif + + // Register GC behaviours in case the array needs to be garbage collected + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); + +#if AS_USE_STLNAMES == 1 + // Same as length + r = engine->RegisterObjectMethod("array", "uint size() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("array", "bool empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertLast + r = engine->RegisterObjectMethod("array", "void push_back(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as removeLast + r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertAt + r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + // Same as removeAt + r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); +#endif +} + +CScriptArray &CScriptArray::operator=(const CScriptArray &other) +{ + // Only perform the copy if the array types are the same + if( &other != this && + other.GetArrayObjectType() == GetArrayObjectType() ) + { + // Make sure the arrays are of the same size + Resize(other.buffer->numElements); + + // Copy the value of each element + CopyBuffer(buffer, other.buffer); + } + + return *this; +} + +CScriptArray::CScriptArray(asITypeInfo *ti, void *buf) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + asIScriptEngine *engine = ti->GetEngine(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = engine->GetSizeOfPrimitiveType(subTypeId); + + // Determine the initial size from the buffer + asUINT length = *(asUINT*)buf; + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + // Copy the values of the array elements from the buffer + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + { + CreateBuffer(&buffer, length); + + // Copy the values of the primitive type into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); + } + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) + { + CreateBuffer(&buffer, length); + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); + + // With object handles it is safe to clear the memory in the received buffer + // instead of increasing the ref count. It will save time both by avoiding the + // call the increase ref, and also relieve the engine from having to release + // its references too + memset((((asUINT*)buf)+1), 0, length * elementSize); + } + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) + { + // Only allocate the buffer, but not the objects + subTypeId |= asTYPEID_OBJHANDLE; + CreateBuffer(&buffer, length); + subTypeId &= ~asTYPEID_OBJHANDLE; + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize); + + // For ref types we can do the same as for handles, as they are + // implicitly stored as handles. + memset((((asUINT*)buf)+1), 0, length * elementSize); + } + else + { + // TODO: Optimize by calling the copy constructor of the object instead of + // constructing with the default constructor and then assigning the value + // TODO: With C++11 ideally we should be calling the move constructor, instead + // of the copy constructor as the engine will just discard the objects in the + // buffer afterwards. + CreateBuffer(&buffer, length); + + // For value types we need to call the opAssign for each individual object + for( asUINT n = 0; n < length; n++ ) + { + void *obj = At(n); + asBYTE *srcObj = (asBYTE*)buf; + srcObj += 4 + n*ti->GetSubType()->GetSize(); + engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); + } + } + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +CScriptArray::CScriptArray(asUINT length, asITypeInfo *ti) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, length); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +CScriptArray::CScriptArray(const CScriptArray &other) +{ + refCount = 1; + gcFlag = false; + objType = other.objType; + objType->AddRef(); + buffer = 0; + + Precache(); + + elementSize = other.elementSize; + + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + + CreateBuffer(&buffer, 0); + + // Copy the content + *this = other; +} + +CScriptArray::CScriptArray(asUINT length, void *defVal, asITypeInfo *ti) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, length); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + + // Initialize the elements with the default value + for( asUINT n = 0; n < GetSize(); n++ ) + SetValue(n, defVal); +} + +void CScriptArray::SetValue(asUINT index, void *value) +{ + // At() will take care of the out-of-bounds checking, though + // if called from the application then nothing will be done + void *ptr = At(index); + if( ptr == 0 ) return; + + if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) ) + objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType()); + else if( subTypeId & asTYPEID_OBJHANDLE ) + { + void *tmp = *(void**)ptr; + *(void**)ptr = *(void**)value; + objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType()); + if( tmp ) + objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType()); + } + else if( subTypeId == asTYPEID_BOOL || + subTypeId == asTYPEID_INT8 || + subTypeId == asTYPEID_UINT8 ) + *(char*)ptr = *(char*)value; + else if( subTypeId == asTYPEID_INT16 || + subTypeId == asTYPEID_UINT16 ) + *(short*)ptr = *(short*)value; + else if( subTypeId == asTYPEID_INT32 || + subTypeId == asTYPEID_UINT32 || + subTypeId == asTYPEID_FLOAT || + subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles + *(int*)ptr = *(int*)value; + else if( subTypeId == asTYPEID_INT64 || + subTypeId == asTYPEID_UINT64 || + subTypeId == asTYPEID_DOUBLE ) + *(double*)ptr = *(double*)value; +} + +CScriptArray::~CScriptArray() +{ + if( buffer ) + { + DeleteBuffer(buffer); + buffer = 0; + } + if( objType ) objType->Release(); +} + +asUINT CScriptArray::GetSize() const +{ + return buffer->numElements; +} + +bool CScriptArray::IsEmpty() const +{ + return buffer->numElements == 0; +} + +void CScriptArray::Reserve(asUINT maxElements) +{ + if( maxElements <= buffer->maxElements ) + return; + + if( !CheckMaxSize(maxElements) ) + return; + + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements)); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements; + newBuffer->maxElements = maxElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } + + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); + + // Release the old buffer + userFree(buffer); + + buffer = newBuffer; +} + +void CScriptArray::Resize(asUINT numElements) +{ + if( !CheckMaxSize(numElements) ) + return; + + Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); +} + +void CScriptArray::RemoveRange(asUINT start, asUINT count) +{ + if (count == 0) + return; + + if( buffer == 0 || start > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + // Cap count to the end of the array + if (start + count > buffer->numElements) + count = buffer->numElements - start; + + // Destroy the elements that are being removed + Destruct(buffer, start, start + count); + + // Compact the elements + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); + buffer->numElements -= count; +} + +// Internal +void CScriptArray::Resize(int delta, asUINT at) +{ + if( delta < 0 ) + { + if( -delta > (int)buffer->numElements ) + delta = -(int)buffer->numElements; + if( at > buffer->numElements + delta ) + at = buffer->numElements + delta; + } + else if( delta > 0 ) + { + // Make sure the array size isn't too large for us to handle + if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) ) + return; + + if( at > buffer->numElements ) + at = buffer->numElements; + } + + if( delta == 0 ) return; + + if( buffer->maxElements < buffer->numElements + delta ) + { + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta))); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements + delta; + newBuffer->maxElements = newBuffer->numElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } + + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, at*elementSize); + if( at < buffer->numElements ) + memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); + + // Initialize the new elements with default values + Construct(newBuffer, at, at+delta); + + // Release the old buffer + userFree(buffer); + + buffer = newBuffer; + } + else if( delta < 0 ) + { + Destruct(buffer, at, at-delta); + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); + buffer->numElements += delta; + } + else + { + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); + Construct(buffer, at, at+delta); + buffer->numElements += delta; + } +} + +// internal +bool CScriptArray::CheckMaxSize(asUINT numElements) +{ + // This code makes sure the size of the buffer that is allocated + // for the array doesn't overflow and becomes smaller than requested + + asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1; + if( elementSize > 0 ) + maxSize /= elementSize; + + if( numElements > maxSize ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Too large array size"); + + return false; + } + + // OK + return true; +} + +asITypeInfo *CScriptArray::GetArrayObjectType() const +{ + return objType; +} + +int CScriptArray::GetArrayTypeId() const +{ + return objType->GetTypeId(); +} + +int CScriptArray::GetElementTypeId() const +{ + return subTypeId; +} + +void CScriptArray::InsertAt(asUINT index, void *value) +{ + if( index > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } + + // Make room for the new element + Resize(1, index); + + // Set the value of the new element + SetValue(index, value); +} + +void CScriptArray::InsertAt(asUINT index, const CScriptArray &arr) +{ + if (index > buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + if (objType != arr.objType) + { + // This shouldn't really be possible to happen when + // called from a script, but let's check for it anyway + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Mismatching array types"); + return; + } + + asUINT elements = arr.GetSize(); + Resize(elements, index); + if (&arr != this) + { + for (asUINT n = 0; n < arr.GetSize(); n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + } + else + { + // The array that is being inserted is the same as this one. + // So we should iterate over the elements before the index, + // and then the elements after + for (asUINT n = 0; n < index; n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + + for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + index + m, value); + } + } +} + +void CScriptArray::InsertLast(void *value) +{ + InsertAt(buffer->numElements, value); +} + +void CScriptArray::RemoveAt(asUINT index) +{ + if( index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } + + // Remove the element + Resize(-1, index); +} + +void CScriptArray::RemoveLast() +{ + RemoveAt(buffer->numElements-1); +} + +// Return a pointer to the array element. Returns 0 if the index is out of bounds +const void *CScriptArray::At(asUINT index) const +{ + if( buffer == 0 || index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return 0; + } + + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + return *(void**)(buffer->data + elementSize*index); + else + return buffer->data + elementSize*index; +} +void *CScriptArray::At(asUINT index) +{ + return const_cast(const_cast(this)->At(index)); +} + +void *CScriptArray::GetBuffer() +{ + return buffer->data; +} + + +// internal +void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements) +{ + *buf = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements)); + + if( *buf ) + { + (*buf)->numElements = numElements; + (*buf)->maxElements = numElements; + Construct(*buf, 0, numElements); + } + else + { + // Oops, out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + } +} + +// internal +void CScriptArray::DeleteBuffer(SArrayBuffer *buf) +{ + Destruct(buf, 0, buf->numElements); + + // Free the buffer + userFree(buf); +} + +// internal +void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) +{ + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Create an object using the default constructor/factory for each element + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); + + asIScriptEngine *engine = objType->GetEngine(); + asITypeInfo *subType = objType->GetSubType(); + + for( ; d < max; d++ ) + { + *d = (void*)engine->CreateScriptObject(subType); + if( *d == 0 ) + { + // Set the remaining entries to null so the destructor + // won't attempt to destroy invalid objects later + memset(d, 0, sizeof(void*)*(max-d)); + + // There is no need to set an exception on the context, + // as CreateScriptObject has already done that + return; + } + } + } + else + { + // Set all elements to zero whether they are handles or primitives + void *d = (void*)(buf->data + start * elementSize); + memset(d, 0, (end-start)*elementSize); + } +} + +// internal +void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end) +{ + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + asIScriptEngine *engine = objType->GetEngine(); + + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); + + for( ; d < max; d++ ) + { + if( *d ) + engine->ReleaseScriptObject(*d, objType->GetSubType()); + } + } +} + + +// internal +bool CScriptArray::Less(const void *a, const void *b, bool asc) +{ + if( !asc ) + { + // Swap items + const void *TEMP = a; + a = b; + b = TEMP; + } + + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) < *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall in this case + #undef COMPARE + } + } + + return false; +} + +void CScriptArray::Reverse() +{ + asUINT size = GetSize(); + + if( size >= 2 ) + { + asBYTE TEMP[16]; + + for( asUINT i = 0; i < size / 2; i++ ) + { + Copy(TEMP, GetArrayItemPointer(i)); + Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1)); + Copy(GetArrayItemPointer(size - i - 1), TEMP); + } + } +} + +bool CScriptArray::operator==(const CScriptArray &other) const +{ + if( objType != other.objType ) + return false; + + if( GetSize() != other.GetSize() ) + return false; + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Check if all elements are equal + bool isEqual = true; + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + for( asUINT n = 0; n < GetSize(); n++ ) + if( !Equals(At(n), other.At(n), cmpContext, cache) ) + { + isEqual = false; + break; + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return isEqual; +} + +// internal +bool CScriptArray::Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const +{ + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) == *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall here + #undef COMPARE + } + } + else + { + int r = 0; + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Allow the find to work even if the array contains null handles + if( *(void**)a == *(void**)b ) return true; + } + + // Execute object opEquals if available + if( cache && cache->eqFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->eqFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return ctx->GetReturnByte() != 0; + + return false; + } + + // Execute object opCmp if available + if( cache && cache->cmpFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return (int)ctx->GetReturnDWord() == 0; + + return false; + } + } + + return false; +} + +int CScriptArray::FindByRef(void *ref) const +{ + return FindByRef(0, ref); +} + +int CScriptArray::FindByRef(asUINT startAt, void *ref) const +{ + // Find the matching element by its reference + asUINT size = GetSize(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Dereference the pointer + ref = *(void**)ref; + for( asUINT i = startAt; i < size; i++ ) + { + if( *(void**)At(i) == ref ) + return i; + } + } + else + { + // Compare the reference directly + for( asUINT i = startAt; i < size; i++ ) + { + if( At(i) == ref ) + return i; + } + } + + return -1; +} + +int CScriptArray::Find(void *value) const +{ + return Find(0, value); +} + +int CScriptArray::Find(asUINT startAt, void *value) const +{ + // Check if the subtype really supports find() + // TODO: Can't this be done at compile time too by the template callback + SArrayCache *cache = 0; + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS ) +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); +#else + sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); +#endif + else +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); +#else + sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); +#endif + ctx->SetException(tmp); + } + + return -1; + } + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Find the matching element + int ret = -1; + asUINT size = GetSize(); + + for( asUINT i = startAt; i < size; i++ ) + { + // value passed by reference + if( Equals(At(i), value, cmpContext, cache) ) + { + ret = (int)i; + break; + } + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return ret; +} + + + +// internal +// Copy object handle or primitive value +// Even in arrays of objects the objects are allocated on +// the heap and the array stores the pointers to the objects +void CScriptArray::Copy(void *dst, void *src) +{ + memcpy(dst, src, elementSize); +} + + +// internal +// Return pointer to array item (object handle or primitive value) +void *CScriptArray::GetArrayItemPointer(int index) +{ + return buffer->data + index * elementSize; +} + +// internal +// Return pointer to data in buffer (object or primitive) +void *CScriptArray::GetDataPointer(void *buf) +{ + if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Real address of object + return reinterpret_cast(*(size_t*)buf); + } + else + { + // Primitive is just a raw data + return buf; + } +} + + +// Sort ascending +void CScriptArray::SortAsc() +{ + Sort(0, GetSize(), true); +} + +// Sort ascending +void CScriptArray::SortAsc(asUINT startAt, asUINT count) +{ + Sort(startAt, count, true); +} + +// Sort descending +void CScriptArray::SortDesc() +{ + Sort(0, GetSize(), false); +} + +// Sort descending +void CScriptArray::SortDesc(asUINT startAt, asUINT count) +{ + Sort(startAt, count, false); +} + + +// internal +void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) +{ + // Subtype isn't primitive and doesn't have opCmp + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + if( !cache || cache->cmpFunc == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS ) +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName()); +#else + sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName()); +#endif + else +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName()); +#else + sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName()); +#endif + + ctx->SetException(tmp); + } + + return; + } + } + + // No need to sort + if( count < 2 ) + { + return; + } + + int start = startAt; + int end = startAt + count; + + // Check if we could access invalid item while sorting + if( start >= (int)buffer->numElements || end > (int)buffer->numElements ) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if( ctx ) + { + ctx->SetException("Index out of bounds"); + } + + return; + } + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + cmpContext = objType->GetEngine()->RequestContext(); + + // Do the sorting + struct { + bool asc; + asIScriptContext *cmpContext; + asIScriptFunction *cmpFunc; + bool operator()(void *a, void *b) const + { + if( !asc ) + { + // Swap items + void *TEMP = a; + a = b; + b = TEMP; + } + + int r = 0; + + // Allow sort to work even if the array contains null handles + if( a == 0 ) return true; + if( b == 0 ) return false; + + // Execute object opCmp + if( cmpFunc ) + { + // TODO: Add proper error handling + r = cmpContext->Prepare(cmpFunc); assert(r >= 0); + r = cmpContext->SetObject(a); assert(r >= 0); + r = cmpContext->SetArgObject(0, b); assert(r >= 0); + r = cmpContext->Execute(); + + if( r == asEXECUTION_FINISHED ) + { + return (int)cmpContext->GetReturnDWord() < 0; + } + } + + return false; + } + } customLess = {asc, cmpContext, cache ? cache->cmpFunc : 0}; + std::sort((void**)GetArrayItemPointer(start), (void**)GetArrayItemPointer(end), customLess); + + // Clean up + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } + } + else + { + // TODO: Use std::sort for primitive types too + + // Insertion sort + asBYTE tmp[16]; + for( int i = start + 1; i < end; i++ ) + { + Copy(tmp, GetArrayItemPointer(i)); + + int j = i - 1; + + while( j >= start && Less(GetDataPointer(tmp), At(j), asc) ) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + } +} + +// Sort with script callback for comparing elements +void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) +{ + // No need to sort + if (count < 2) + return; + + // Check if we could access invalid item while sorting + asUINT start = startAt; + asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; + if (end > buffer->numElements) + end = buffer->numElements; + + if (start >= buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if (ctx) + ctx->SetException("Index out of bounds"); + + return; + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if (cmpContext) + { + if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) + isNested = true; + else + cmpContext = 0; + } + if (cmpContext == 0) + cmpContext = objType->GetEngine()->RequestContext(); + + // Insertion sort + asBYTE tmp[16]; + for (asUINT i = start + 1; i < end; i++) + { + Copy(tmp, GetArrayItemPointer(i)); + + asUINT j = i - 1; + + while (j != 0xFFFFFFFF && j >= start ) + { + cmpContext->Prepare(func); + cmpContext->SetArgAddress(0, GetDataPointer(tmp)); + cmpContext->SetArgAddress(1, At(j)); + int r = cmpContext->Execute(); + if (r != asEXECUTION_FINISHED) + break; + if (*(bool*)(cmpContext->GetAddressOfReturnValue())) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + else + break; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + + if (cmpContext) + { + if (isNested) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if (state == asEXECUTION_ABORTED) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } +} + +// internal +void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) +{ + asIScriptEngine *engine = objType->GetEngine(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Copy the references and increase the reference counters + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + for( ; d < max; d++, s++ ) + { + void *tmp = *d; + *d = *s; + if( *d ) + engine->AddRefScriptObject(*d, objType->GetSubType()); + // Release the old ref after incrementing the new to avoid problem incase it is the same ref + if( tmp ) + engine->ReleaseScriptObject(tmp, objType->GetSubType()); + } + } + } + else + { + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + // Call the assignment operator on all of the objects + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + asITypeInfo *subType = objType->GetSubType(); + for( ; d < max; d++, s++ ) + engine->AssignScriptObject(*d, *s, subType); + } + else + { + // Primitives are copied byte for byte + memcpy(dst->data, src->data, count*elementSize); + } + } + } +} + +// internal +// Precache some info +void CScriptArray::Precache() +{ + subTypeId = objType->GetSubTypeId(); + + // Check if it is an array of objects. Only for these do we need to cache anything + // Type ids for primitives and enums only has the sequence number part + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + return; + + // The opCmp and opEquals methods are cached because the searching for the + // methods is quite time consuming if a lot of array objects are created. + + // First check if a cache already exists for this array type + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) return; + + // We need to make sure the cache is created only once, even + // if multiple threads reach the same point at the same time + asAcquireExclusiveLock(); + + // Now that we got the lock, we need to check again to make sure the + // cache wasn't created while we were waiting for the lock + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) + { + asReleaseExclusiveLock(); + return; + } + + // Create the cache + cache = reinterpret_cast(userAlloc(sizeof(SArrayCache))); + if( !cache ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + asReleaseExclusiveLock(); + return; + } + memset(cache, 0, sizeof(SArrayCache)); + + // If the sub type is a handle to const, then the methods must be const too + bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; + + asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + if( subType ) + { + for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) + { + asIScriptFunction *func = subType->GetMethodByIndex(i); + + if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) ) + { + asDWORD flags = 0; + int returnTypeId = func->GetReturnTypeId(&flags); + + // The method must not return a reference + if( flags != asTM_NONE ) + continue; + + // opCmp returns an int and opEquals returns a bool + bool isCmp = false, isEq = false; + if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 ) + isCmp = true; + if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 ) + isEq = true; + + if( !isCmp && !isEq ) + continue; + + // The parameter must either be a reference to the subtype or a handle to the subtype + int paramTypeId; + func->GetParam(0, ¶mTypeId, &flags); + + if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) ) + continue; + + if( (flags & asTM_INREF) ) + { + if( (paramTypeId & asTYPEID_OBJHANDLE) || (mustBeConst && !(flags & asTM_CONST)) ) + continue; + } + else if( paramTypeId & asTYPEID_OBJHANDLE ) + { + if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) ) + continue; + } + else + continue; + + if( isCmp ) + { + if( cache->cmpFunc || cache->cmpFuncReturnCode ) + { + cache->cmpFunc = 0; + cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->cmpFunc = func; + } + else if( isEq ) + { + if( cache->eqFunc || cache->eqFuncReturnCode ) + { + cache->eqFunc = 0; + cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->eqFunc = func; + } + } + } + } + + if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 ) + cache->eqFuncReturnCode = asNO_FUNCTION; + if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 ) + cache->cmpFuncReturnCode = asNO_FUNCTION; + + // Set the user data only at the end so others that retrieve it will know it is complete + objType->SetUserData(cache, ARRAY_CACHE); + + asReleaseExclusiveLock(); +} + +// GC behaviour +void CScriptArray::EnumReferences(asIScriptEngine *engine) +{ + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the array is modified + + // If the array is holding handles, then we need to notify the GC of them + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + void **d = (void**)buffer->data; + + asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + // For reference types we need to notify the GC of each instance + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->GCEnumCallback(d[n]); + } + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->ForwardGCEnumReferences(d[n], subType); + } + } + } +} + +// GC behaviour +void CScriptArray::ReleaseAllHandles(asIScriptEngine *) +{ + // Resizing to zero will release everything + Resize(0); +} + +void CScriptArray::AddRef() const +{ + // Clear the GC flag then increase the counter + gcFlag = false; + asAtomicInc(refCount); +} + +void CScriptArray::Release() const +{ + // Clearing the GC flag then descrease the counter + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + // When reaching 0 no more references to this instance + // exists and the object should be destroyed + this->~CScriptArray(); + userFree(const_cast(this)); + } +} + +// GC behaviour +int CScriptArray::GetRefCount() +{ + return refCount; +} + +// GC behaviour +void CScriptArray::SetFlag() +{ + gcFlag = true; +} + +// GC behaviour +bool CScriptArray::GetFlag() +{ + return gcFlag; +} + +//-------------------------------------------- +// Generic calling conventions + +static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); +} + +static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); +} + +static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + void *buf = gen->GetArgAddress(1); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); +} + +static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); + void *defVal = gen->GetArgAddress(2); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); +} + +static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); +} + +static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) +{ + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *self = *other; + gen->SetReturnObject(self); +} + +static void ScriptArrayEquals_Generic(asIScriptGeneric *gen) +{ + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnByte(self->operator==(*other)); +} + +static void ScriptArrayFind_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(value)); +} + +static void ScriptArrayFind2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(index, value)); +} + +static void ScriptArrayFindByRef_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(value)); +} + +static void ScriptArrayFindByRef2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(index, value)); +} + +static void ScriptArrayAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + gen->SetReturnAddress(self->At(index)); +} + +static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, value); +} + +static void ScriptArrayInsertAtArray_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, *array); +} + +static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveAt(index); +} + +static void ScriptArrayRemoveRange_Generic(asIScriptGeneric *gen) +{ + asUINT start = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveRange(start, count); +} + +static void ScriptArrayInsertLast_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertLast(value); +} + +static void ScriptArrayRemoveLast_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveLast(); +} + +static void ScriptArrayLength_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + gen->SetReturnDWord(self->GetSize()); +} + +static void ScriptArrayResize_Generic(asIScriptGeneric *gen) +{ + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + self->Resize(size); +} + +static void ScriptArrayReserve_Generic(asIScriptGeneric *gen) +{ + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reserve(size); +} + +static void ScriptArraySortAsc_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(); +} + +static void ScriptArrayReverse_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reverse(); +} + +static void ScriptArrayIsEmpty_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->IsEmpty(); +} + +static void ScriptArraySortAsc2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(index, count); +} + +static void ScriptArraySortDesc_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(); +} + +static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(index, count); +} + +static void ScriptArraySortCallback_Generic(asIScriptGeneric *gen) +{ + asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); + asUINT startAt = gen->GetArgDWord(1); + asUINT count = gen->GetArgDWord(2); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Sort(callback, startAt, count); +} + +static void ScriptArrayAddRef_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->AddRef(); +} + +static void ScriptArrayRelease_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Release(); +} + +static void ScriptArrayGetRefCount_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetRefCount(); +} + +static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SetFlag(); +} + +static void ScriptArrayGetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetFlag(); +} + +static void ScriptArrayEnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); +} + +static void RegisterScriptArray_Generic(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptArraySetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptArrayGetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptArrayEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptArrayReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + +END_AS_NAMESPACE diff --git a/TestRunner/angelscript_addons/scriptarray/scriptarray.h b/TestRunner/angelscript_addons/scriptarray/scriptarray.h new file mode 100644 index 0000000..4903a97 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptarray/scriptarray.h @@ -0,0 +1,142 @@ +#ifndef SCRIPTARRAY_H +#define SCRIPTARRAY_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + +// Some prefer to use property accessors to get/set the length of the array +// This option registers the accessors instead of the method length() +#ifndef AS_USE_ACCESSORS +#define AS_USE_ACCESSORS 0 +#endif + +BEGIN_AS_NAMESPACE + +struct SArrayBuffer; +struct SArrayCache; + +class CScriptArray +{ +public: + // Set the memory functions that should be used by all CScriptArrays + static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); + + // Factory functions + static CScriptArray *Create(asITypeInfo *ot); + static CScriptArray *Create(asITypeInfo *ot, asUINT length); + static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); + static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); + + // Memory management + void AddRef() const; + void Release() const; + + // Type information + asITypeInfo *GetArrayObjectType() const; + int GetArrayTypeId() const; + int GetElementTypeId() const; + + // Get the current size + asUINT GetSize() const; + + // Returns true if the array is empty + bool IsEmpty() const; + + // Pre-allocates memory for elements + void Reserve(asUINT maxElements); + + // Resize the array + void Resize(asUINT numElements); + + // Get a pointer to an element. Returns 0 if out of bounds + void *At(asUINT index); + const void *At(asUINT index) const; + + // Set value of an element. + // The value arg should be a pointer to the value that will be copied to the element. + // Remember, if the array holds handles the value parameter should be the + // address of the handle. The refCount of the object will also be incremented + void SetValue(asUINT index, void *value); + + // Copy the contents of one array to another (only if the types are the same) + CScriptArray &operator=(const CScriptArray&); + + // Compare two arrays + bool operator==(const CScriptArray &) const; + + // Array manipulation + void InsertAt(asUINT index, void *value); + void InsertAt(asUINT index, const CScriptArray &arr); + void InsertLast(void *value); + void RemoveAt(asUINT index); + void RemoveLast(); + void RemoveRange(asUINT start, asUINT count); + void SortAsc(); + void SortDesc(); + void SortAsc(asUINT startAt, asUINT count); + void SortDesc(asUINT startAt, asUINT count); + void Sort(asUINT startAt, asUINT count, bool asc); + void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); + void Reverse(); + int Find(void *value) const; + int Find(asUINT startAt, void *value) const; + int FindByRef(void *ref) const; + int FindByRef(asUINT startAt, void *ref) const; + + // Return the address of internal buffer for direct manipulation of elements + void *GetBuffer(); + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + +protected: + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SArrayBuffer *buffer; + int elementSize; + int subTypeId; + + // Constructors + CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptArray(asUINT length, asITypeInfo *ot); + CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); + CScriptArray(const CScriptArray &other); + virtual ~CScriptArray(); + + bool Less(const void *a, const void *b, bool asc); + void *GetArrayItemPointer(int index); + void *GetDataPointer(void *buffer); + void Copy(void *dst, void *src); + void Precache(); + bool CheckMaxSize(asUINT numElements); + void Resize(int delta, asUINT at); + void CreateBuffer(SArrayBuffer **buf, asUINT numElements); + void DeleteBuffer(SArrayBuffer *buf); + void CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src); + void Construct(SArrayBuffer *buf, asUINT start, asUINT end); + void Destruct(SArrayBuffer *buf, asUINT start, asUINT end); + bool Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const; +}; + +void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray); + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.cpp b/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.cpp new file mode 100644 index 0000000..97b2833 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.cpp @@ -0,0 +1,1167 @@ +#include "scriptbuilder.h" +#include +#include +using namespace std; + +#include +#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(__S3E__) +#include +#endif +#ifdef _WIN32_WCE +#include // For GetModuleFileName() +#endif + +#if defined(__S3E__) || defined(__APPLE__) || defined(__GNUC__) +#include // For getcwd() +#endif + +BEGIN_AS_NAMESPACE + +// Helper functions +static string GetCurrentDir(); +static string GetAbsolutePath(const string &path); + + +CScriptBuilder::CScriptBuilder() +{ + engine = 0; + module = 0; + + includeCallback = 0; + includeParam = 0; + + pragmaCallback = 0; + pragmaParam = 0; +} + +void CScriptBuilder::SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam) +{ + includeCallback = callback; + includeParam = userParam; +} + +void CScriptBuilder::SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) +{ + pragmaCallback = callback; + pragmaParam = userParam; +} + +int CScriptBuilder::StartNewModule(asIScriptEngine *inEngine, const char *moduleName) +{ + if(inEngine == 0 ) return -1; + + engine = inEngine; + module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE); + if( module == 0 ) + return -1; + + ClearAll(); + + return 0; +} + +asIScriptEngine *CScriptBuilder::GetEngine() +{ + return engine; +} + +asIScriptModule *CScriptBuilder::GetModule() +{ + return module; +} + +unsigned int CScriptBuilder::GetSectionCount() const +{ + return (unsigned int)(includedScripts.size()); +} + +string CScriptBuilder::GetSectionName(unsigned int idx) const +{ + if( idx >= includedScripts.size() ) return ""; + +#ifdef _WIN32 + set::const_iterator it = includedScripts.begin(); +#else + set::const_iterator it = includedScripts.begin(); +#endif + while( idx-- > 0 ) it++; + return *it; +} + +// Returns 1 if the section was included +// Returns 0 if the section was not included because it had already been included before +// Returns <0 if there was an error +int CScriptBuilder::AddSectionFromFile(const char *filename) +{ + // The file name stored in the set should be the fully resolved name because + // it is possible to name the same file in multiple ways using relative paths. + string fullpath = GetAbsolutePath(filename); + + if( IncludeIfNotAlreadyIncluded(fullpath.c_str()) ) + { + int r = LoadScriptSection(fullpath.c_str()); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; +} + +// Returns 1 if the section was included +// Returns 0 if the section was not included because it had already been included before +// Returns <0 if there was an error +int CScriptBuilder::AddSectionFromMemory(const char *sectionName, const char *scriptCode, unsigned int scriptLength, int lineOffset) +{ + if( IncludeIfNotAlreadyIncluded(sectionName) ) + { + int r = ProcessScriptSection(scriptCode, scriptLength, sectionName, lineOffset); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; +} + +int CScriptBuilder::BuildModule() +{ + return Build(); +} + +void CScriptBuilder::DefineWord(const char *word) +{ + string sword = word; + if( definedWords.find(sword) == definedWords.end() ) + { + definedWords.insert(sword); + } +} + +void CScriptBuilder::ClearAll() +{ + includedScripts.clear(); + +#if AS_PROCESS_METADATA == 1 + currentClass = ""; + currentNamespace = ""; + + foundDeclarations.clear(); + typeMetadataMap.clear(); + funcMetadataMap.clear(); + varMetadataMap.clear(); +#endif +} + +bool CScriptBuilder::IncludeIfNotAlreadyIncluded(const char *filename) +{ + string scriptFile = filename; + if( includedScripts.find(scriptFile) != includedScripts.end() ) + { + // Already included + return false; + } + + // Add the file to the set of included sections + includedScripts.insert(scriptFile); + + return true; +} + +int CScriptBuilder::LoadScriptSection(const char *filename) +{ + // Open the script file + string scriptFile = filename; +#if _MSC_VER >= 1500 && !defined(__S3E__) + FILE *f = 0; + fopen_s(&f, scriptFile.c_str(), "rb"); +#else + FILE *f = fopen(scriptFile.c_str(), "rb"); +#endif + if( f == 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to open script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + + // TODO: Write the file where this one was included from + + return -1; + } + + // Determine size of the file + fseek(f, 0, SEEK_END); + int len = ftell(f); + fseek(f, 0, SEEK_SET); + + // On Win32 it is possible to do the following instead + // int len = _filelength(_fileno(f)); + + // Read the entire file + string code; + size_t c = 0; + if( len > 0 ) + { + code.resize(len); + c = fread(&code[0], len, 1, f); + } + + fclose(f); + + if( c == 0 && len > 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to load script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + return -1; + } + + // Process the script section even if it is zero length so that the name is registered + return ProcessScriptSection(code.c_str(), (unsigned int)(code.length()), filename, 0); +} + +int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset) +{ + vector includes; + + // Perform a superficial parsing of the script first to store the metadata + if( length ) + modifiedScript.assign(script, length); + else + modifiedScript = script; + + // First perform the checks for #if directives to exclude code that shouldn't be compiled + unsigned int pos = 0; + int nested = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_UNKNOWN && modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + // Is this an #if directive? + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + string token; + token.assign(&modifiedScript[pos], len); + + pos += len; + + if( token == "if" ) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_IDENTIFIER ) + { + string word; + word.assign(&modifiedScript[pos], len); + + // Overwrite the #if directive with space characters to avoid compiler error + pos += len; + OverwriteCode(start, pos-start); + + // Has this identifier been defined by the application or not? + if( definedWords.find(word) == definedWords.end() ) + { + // Exclude all the code until and including the #endif + pos = ExcludeCode(pos); + } + else + { + nested++; + } + } + } + else if( token == "endif" ) + { + // Only remove the #endif if there was a matching #if + if( nested > 0 ) + { + OverwriteCode(start, pos-start); + nested--; + } + } + } + else + pos += len; + } + +#if AS_PROCESS_METADATA == 1 + // Preallocate memory + string name, declaration; + vector metadata; + declaration.reserve(100); +#endif + + // Then check for meta data and #include directives + pos = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_COMMENT || t == asTC_WHITESPACE ) + { + pos += len; + continue; + } + +#if AS_PROCESS_METADATA == 1 + // Check if class + if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) + { + // Get the identifier after "class" + do + { + pos += len; + if( pos >= modifiedScript.size() ) + { + t = asTC_UNKNOWN; + break; + } + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( t == asTC_IDENTIFIER ) + { + currentClass = modifiedScript.substr(pos,len); + + // Search until first { or ; is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of class section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + else if (modifiedScript[pos] == ';') + { + // The class declaration has ended and there are no children + currentClass = ""; + pos += len; + break; + } + + // Check next symbol + pos += len; + } + } + + continue; + } + + // Check if end of class + if( currentClass != "" && modifiedScript[pos] == '}' ) + { + currentClass = ""; + pos += len; + continue; + } + + // Check if namespace + if( modifiedScript.substr(pos,len) == "namespace" ) + { + // Get the identifier after "namespace" + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( currentNamespace != "" ) + currentNamespace += "::"; + currentNamespace += modifiedScript.substr(pos,len); + + // Search until first { is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of namespace section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + + // Check next symbol + pos += len; + } + + continue; + } + + // Check if end of namespace + if( currentNamespace != "" && modifiedScript[pos] == '}' ) + { + size_t found = currentNamespace.rfind( "::" ); + if( found != string::npos ) + { + currentNamespace.erase( found ); + } + else + { + currentNamespace = ""; + } + pos += len; + continue; + } + + // Is this the start of metadata? + if( modifiedScript[pos] == '[' ) + { + // Get the metadata string + pos = ExtractMetadata(pos, metadata); + + // Determine what this metadata is for + int type; + ExtractDeclaration(pos, name, declaration, type); + + // Store away the declaration in a map for lookup after the build has completed + if( type > 0 ) + { + SMetadataDecl decl(metadata, name, declaration, type, currentClass, currentNamespace); + foundDeclarations.push_back(decl); + } + } + else +#endif + // Is this a preprocessor directive? + if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_IDENTIFIER ) + { + string token; + token.assign(&modifiedScript[pos], len); + if( token == "include" ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) + { + // Get the include file + string includefile; + includefile.assign(&modifiedScript[pos+1], len-2); + pos += len; + + // Store it for later processing + includes.push_back(includefile); + + // Overwrite the include directive with space characters to avoid compiler error + OverwriteCode(start, pos-start); + } + } + else if (token == "pragma") + { + // Read until the end of the line + pos += len; + for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); + + // Call the pragma callback + string pragmaText(&modifiedScript[start + 7], pos - start - 7); + int r = pragmaCallback ? pragmaCallback(pragmaText, *this, pragmaParam) : -1; + if (r < 0) + { + // TODO: Report the correct line number + engine->WriteMessage(sectionname, 0, 0, asMSGTYPE_ERROR, "Invalid #pragma directive"); + return r; + } + + // Overwrite the pragma directive with space characters to avoid compiler error + OverwriteCode(start, pos - start); + } + } + } + // Don't search for metadata/includes within statement blocks or between tokens in statements + else + { + pos = SkipStatement(pos); + } + } + + // Build the actual script + engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); + module->AddScriptSection(sectionname, modifiedScript.c_str(), modifiedScript.size(), lineOffset); + + if( includes.size() > 0 ) + { + // If the callback has been set, then call it for each included file + if( includeCallback ) + { + for( int n = 0; n < (int)includes.size(); n++ ) + { + int r = includeCallback(includes[n].c_str(), sectionname, this, includeParam); + if( r < 0 ) + return r; + } + } + else + { + // By default we try to load the included file from the relative directory of the current file + + // Determine the path of the current script so that we can resolve relative paths for includes + string path = sectionname; + size_t posOfSlash = path.find_last_of("/\\"); + if( posOfSlash != string::npos ) + path.resize(posOfSlash+1); + else + path = ""; + + // Load the included scripts + for( int n = 0; n < (int)includes.size(); n++ ) + { + // If the include is a relative path, then prepend the path of the originating script + if( includes[n].find_first_of("/\\") != 0 && + includes[n].find_first_of(":") == string::npos ) + { + includes[n] = path + includes[n]; + } + + // Include the script section + int r = AddSectionFromFile(includes[n].c_str()); + if( r < 0 ) + return r; + } + } + } + + return 0; +} + +int CScriptBuilder::Build() +{ + int r = module->Build(); + if( r < 0 ) + return r; + +#if AS_PROCESS_METADATA == 1 + // After the script has been built, the metadata strings should be + // stored for later lookup by function id, type id, and variable index + for( int n = 0; n < (int)foundDeclarations.size(); n++ ) + { + SMetadataDecl *decl = &foundDeclarations[n]; + module->SetDefaultNamespace(decl->nameSpace.c_str()); + if( decl->type == MDT_TYPE ) + { + // Find the type id + int typeId = module->GetTypeIdByDecl(decl->declaration.c_str()); + assert( typeId >= 0 ); + if( typeId >= 0 ) + typeMetadataMap.insert(map >::value_type(typeId, decl->metadata)); + } + else if( decl->type == MDT_FUNC ) + { + if( decl->parentClass == "" ) + { + // Find the function id + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method id + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VIRTPROP ) + { + if( decl->parentClass == "" ) + { + // Find the global virtual property accessors + asIScriptFunction *func = module->GetFunctionByName(("get_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = module->GetFunctionByName(("set_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method virtual property accessors + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByName(("get_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = type->GetMethodByName(("set_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VAR ) + { + if( decl->parentClass == "" ) + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->declaration.c_str()); + assert( varIdx >= 0 ); + if( varIdx >= 0 ) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for( asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i ) + { + const char *name; + objectType->GetProperty(i, &name); + if( decl->declaration == name ) + { + idx = i; + break; + } + } + + // If found, add it + assert( idx >= 0 ); + if( idx >= 0 ) it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + } + } + else if (decl->type == MDT_FUNC_OR_VAR) + { + if (decl->parentClass == "") + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->name.c_str()); + if (varIdx >= 0) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + else + { + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert(func); + if (func) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert(typeId > 0); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if (it == classMetadataMap.end()) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for (asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i) + { + const char *name; + objectType->GetProperty(i, &name); + if (decl->name == name) + { + idx = i; + break; + } + } + + // If found, add it + if (idx >= 0) + it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + else + { + // Look for the matching method instead + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert(func); + if (func) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + } + } + module->SetDefaultNamespace(""); +#endif + + return 0; +} + +int CScriptBuilder::SkipStatement(int pos) +{ + asUINT len = 0; + + // Skip until ; or { whichever comes first + while( pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' && modifiedScript[pos] != '{' ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + pos += len; + } + + // Skip entire statement block + if( pos < (int)modifiedScript.length() && modifiedScript[pos] == '{' ) + { + pos += 1; + + // Find the end of the statement block + int level = 1; + while( level > 0 && pos < (int)modifiedScript.size() ) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_KEYWORD ) + { + if( modifiedScript[pos] == '{' ) + level++; + else if( modifiedScript[pos] == '}' ) + level--; + } + + pos += len; + } + } + else + pos += 1; + + return pos; +} + +// Overwrite all code with blanks until the matching #endif +int CScriptBuilder::ExcludeCode(int pos) +{ + asUINT len = 0; + int nested = 0; + while( pos < (int)modifiedScript.size() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( modifiedScript[pos] == '#' ) + { + modifiedScript[pos] = ' '; + pos++; + + // Is it an #if or #endif directive? + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + string token; + token.assign(&modifiedScript[pos], len); + OverwriteCode(pos, len); + + if( token == "if" ) + { + nested++; + } + else if( token == "endif" ) + { + if( nested-- == 0 ) + { + pos += len; + break; + } + } + } + else if( modifiedScript[pos] != '\n' ) + { + OverwriteCode(pos, len); + } + pos += len; + } + + return pos; +} + +// Overwrite all characters except line breaks with blanks +void CScriptBuilder::OverwriteCode(int start, int len) +{ + char *code = &modifiedScript[start]; + for( int n = 0; n < len; n++ ) + { + if( *code != '\n' ) + *code = ' '; + code++; + } +} + +#if AS_PROCESS_METADATA == 1 +int CScriptBuilder::ExtractMetadata(int pos, vector &metadata) +{ + metadata.clear(); + + // Extract all metadata. They can be separated by whitespace and comments + for (;;) + { + string metadataString = ""; + + // Overwrite the metadata with space characters to allow compilation + modifiedScript[pos] = ' '; + + // Skip opening brackets + pos += 1; + + int level = 1; + asUINT len = 0; + while (level > 0 && pos < (int)modifiedScript.size()) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if (t == asTC_KEYWORD) + { + if (modifiedScript[pos] == '[') + level++; + else if (modifiedScript[pos] == ']') + level--; + } + + // Copy the metadata to our buffer + if (level > 0) + metadataString.append(&modifiedScript[pos], len); + + // Overwrite the metadata with space characters to allow compilation + if (t != asTC_WHITESPACE) + OverwriteCode(pos, len); + + pos += len; + } + + metadata.push_back(metadataString); + + // Check for more metadata. Possibly separated by comments + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + while (t == asTC_COMMENT || t == asTC_WHITESPACE) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if (modifiedScript[pos] != '[') + break; + } + + return pos; +} + +int CScriptBuilder::ExtractDeclaration(int pos, string &name, string &declaration, int &type) +{ + declaration = ""; + type = 0; + + int start = pos; + + std::string token; + asUINT len = 0; + asETokenClass t = asTC_WHITESPACE; + + // Skip white spaces, comments, and leading decorators + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT || + token == "private" || token == "protected" || + token == "shared" || token == "external" || + token == "final" || token == "abstract" ); + + // We're expecting, either a class, interface, function, or variable declaration + if( t == asTC_KEYWORD || t == asTC_IDENTIFIER ) + { + token.assign(&modifiedScript[pos], len); + if( token == "interface" || token == "class" || token == "enum" ) + { + // Skip white spaces and comments + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT ); + + if( t == asTC_IDENTIFIER ) + { + type = MDT_TYPE; + declaration.assign(&modifiedScript[pos], len); + pos += len; + return pos; + } + } + else + { + // For function declarations, store everything up to the start of the + // statement block, except for succeeding decorators (final, override, etc) + + // For variable declaration store just the name as there can only be one + + // We'll only know if the declaration is a variable or function declaration + // when we see the statement block, or absense of a statement block. + bool hasParenthesis = false; + int nestedParenthesis = 0; + declaration.append(&modifiedScript[pos], len); + pos += len; + for(; pos < (int)modifiedScript.size();) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + if (t == asTC_KEYWORD) + { + if (token == "{" && nestedParenthesis == 0) + { + if (hasParenthesis) + { + // We've found the end of a function signature + type = MDT_FUNC; + } + else + { + // We've found a virtual property. Just keep the name + declaration = name; + type = MDT_VIRTPROP; + } + return pos; + } + if ((token == "=" && !hasParenthesis) || token == ";") + { + if (hasParenthesis) + { + // The declaration is ambigous. It can be a variable with initialization, or a function prototype + type = MDT_FUNC_OR_VAR; + } + else + { + // Substitute the declaration with just the name + declaration = name; + type = MDT_VAR; + } + return pos; + } + else if (token == "(") + { + nestedParenthesis++; + + // This is the first parenthesis we encounter. If the parenthesis isn't followed + // by a statement block, then this is a variable declaration, in which case we + // should only store the type and name of the variable, not the initialization parameters. + hasParenthesis = true; + } + else if (token == ")") + { + nestedParenthesis--; + } + } + else if( t == asTC_IDENTIFIER ) + { + name = token; + } + + // Skip trailing decorators + if( !hasParenthesis || nestedParenthesis > 0 || t != asTC_IDENTIFIER || (token != "final" && token != "override") ) + declaration += token; + + pos += len; + } + } + } + + return start; +} + +vector CScriptBuilder::GetMetadataForType(int typeId) +{ + map >::iterator it = typeMetadataMap.find(typeId); + if( it != typeMetadataMap.end() ) + return it->second; + + return vector(); +} + +vector CScriptBuilder::GetMetadataForFunc(asIScriptFunction *func) +{ + if( func ) + { + map >::iterator it = funcMetadataMap.find(func->GetId()); + if( it != funcMetadataMap.end() ) + return it->second; + } + + return vector(); +} + +vector CScriptBuilder::GetMetadataForVar(int varIdx) +{ + map >::iterator it = varMetadataMap.find(varIdx); + if( it != varMetadataMap.end() ) + return it->second; + + return vector(); +} + +vector CScriptBuilder::GetMetadataForTypeProperty(int typeId, int varIdx) +{ + map::iterator typeIt = classMetadataMap.find(typeId); + if(typeIt == classMetadataMap.end()) return vector(); + + map >::iterator propIt = typeIt->second.varMetadataMap.find(varIdx); + if(propIt == typeIt->second.varMetadataMap.end()) return vector(); + + return propIt->second; +} + +vector CScriptBuilder::GetMetadataForTypeMethod(int typeId, asIScriptFunction *method) +{ + if( method ) + { + map::iterator typeIt = classMetadataMap.find(typeId); + if (typeIt == classMetadataMap.end()) return vector(); + + map >::iterator methodIt = typeIt->second.funcMetadataMap.find(method->GetId()); + if(methodIt == typeIt->second.funcMetadataMap.end()) return vector(); + + return methodIt->second; + } + + return vector(); +} +#endif + +string GetAbsolutePath(const string &file) +{ + string str = file; + + // If this is a relative path, complement it with the current path + if( !((str.length() > 0 && (str[0] == '/' || str[0] == '\\')) || + str.find(":") != string::npos) ) + { + str = GetCurrentDir() + "/" + str; + } + + // Replace backslashes for forward slashes + size_t pos = 0; + while( (pos = str.find("\\", pos)) != string::npos ) + str[pos] = '/'; + + // Replace /./ with / + pos = 0; + while( (pos = str.find("/./", pos)) != string::npos ) + str.erase(pos+1, 2); + + // For each /../ remove the parent dir and the /../ + pos = 0; + while( (pos = str.find("/../")) != string::npos ) + { + size_t pos2 = str.rfind("/", pos-1); + if( pos2 != string::npos ) + str.erase(pos2, pos+3-pos2); + else + { + // The path is invalid + break; + } + } + + return str; +} + +string GetCurrentDir() +{ + char buffer[1024]; +#if defined(_MSC_VER) || defined(_WIN32) + #ifdef _WIN32_WCE + static TCHAR apppath[MAX_PATH] = TEXT(""); + if (!apppath[0]) + { + GetModuleFileName(NULL, apppath, MAX_PATH); + + int appLen = _tcslen(apppath); + + // Look for the last backslash in the path, which would be the end + // of the path itself and the start of the filename. We only want + // the path part of the exe's full-path filename + // Safety is that we make sure not to walk off the front of the + // array (in case the path is nothing more than a filename) + while (appLen > 1) + { + if (apppath[appLen-1] == TEXT('\\')) + break; + appLen--; + } + + // Terminate the string after the trailing backslash + apppath[appLen] = TEXT('\0'); + } + #ifdef _UNICODE + wcstombs(buffer, apppath, min(1024, wcslen(apppath)*sizeof(wchar_t))); + #else + memcpy(buffer, apppath, min(1024, strlen(apppath))); + #endif + + return buffer; + #elif defined(__S3E__) + // Marmalade uses its own portable C library + return getcwd(buffer, (int)1024); + #elif _XBOX_VER >= 200 + // XBox 360 doesn't support the getcwd function, just use the root folder + return "game:/"; + #elif defined(_M_ARM) + // TODO: How to determine current working dir on Windows Phone? + return ""; + #else + return _getcwd(buffer, (int)1024); + #endif // _MSC_VER +#elif defined(__APPLE__) || defined(__linux__) + return getcwd(buffer, 1024); +#else + return ""; +#endif +} + +END_AS_NAMESPACE + + diff --git a/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.h b/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.h new file mode 100644 index 0000000..c11f1b9 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptbuilder/scriptbuilder.h @@ -0,0 +1,216 @@ +#ifndef SCRIPTBUILDER_H +#define SCRIPTBUILDER_H + +//--------------------------- +// Compilation settings +// + +// Set this flag to turn on/off metadata processing +// 0 = off +// 1 = on +#ifndef AS_PROCESS_METADATA +#define AS_PROCESS_METADATA 1 +#endif + +// TODO: Implement flags for turning on/off include directives and conditional programming + + + +//--------------------------- +// Declaration +// + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +#if defined(_MSC_VER) && _MSC_VER <= 1200 +// disable the annoying warnings on MSVC 6 +#pragma warning (disable:4786) +#endif + +#include +#include +#include +#include +#include // _strcmpi + +BEGIN_AS_NAMESPACE + +class CScriptBuilder; + +// This callback will be called for each #include directive encountered by the +// builder. The callback should call the AddSectionFromFile or AddSectionFromMemory +// to add the included section to the script. If the include cannot be resolved +// then the function should return a negative value to abort the compilation. +typedef int (*INCLUDECALLBACK_t)(const char *include, const char *from, CScriptBuilder *builder, void *userParam); + +// This callback will be called for each #pragma directive encountered by the builder. +// The application can interpret the pragmaText and decide what do to based on that. +// If the callback returns a negative value the builder will report an error and abort the compilation. +typedef int(*PRAGMACALLBACK_t)(const std::string &pragmaText, CScriptBuilder &builder, void *userParam); + +// Helper class for loading and pre-processing script files to +// support include directives and metadata declarations +class CScriptBuilder +{ +public: + CScriptBuilder(); + + // Start a new module + int StartNewModule(asIScriptEngine *engine, const char *moduleName); + + // Load a script section from a file on disk + // Returns 1 if the file was included + // 0 if the file had already been included before + // <0 on error + int AddSectionFromFile(const char *filename); + + // Load a script section from memory + // Returns 1 if the section was included + // 0 if a section with the same name had already been included before + // <0 on error + int AddSectionFromMemory(const char *sectionName, + const char *scriptCode, + unsigned int scriptLength = 0, + int lineOffset = 0); + + // Build the added script sections + int BuildModule(); + + // Returns the engine + asIScriptEngine *GetEngine(); + + // Returns the current module + asIScriptModule *GetModule(); + + // Register the callback for resolving include directive + void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); + + // Register the callback for resolving pragma directive + void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); + + // Add a pre-processor define for conditional compilation + void DefineWord(const char *word); + + // Enumerate included script sections + unsigned int GetSectionCount() const; + std::string GetSectionName(unsigned int idx) const; + +#if AS_PROCESS_METADATA == 1 + // Get metadata declared for classes, interfaces, and enums + std::vector GetMetadataForType(int typeId); + + // Get metadata declared for functions + std::vector GetMetadataForFunc(asIScriptFunction *func); + + // Get metadata declared for global variables + std::vector GetMetadataForVar(int varIdx); + + // Get metadata declared for class variables + std::vector GetMetadataForTypeProperty(int typeId, int varIdx); + + // Get metadata declared for class methods + std::vector GetMetadataForTypeMethod(int typeId, asIScriptFunction *method); +#endif + +protected: + void ClearAll(); + int Build(); + int ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset); + int LoadScriptSection(const char *filename); + bool IncludeIfNotAlreadyIncluded(const char *filename); + + int SkipStatement(int pos); + + int ExcludeCode(int start); + void OverwriteCode(int start, int len); + + asIScriptEngine *engine; + asIScriptModule *module; + std::string modifiedScript; + + INCLUDECALLBACK_t includeCallback; + void *includeParam; + + PRAGMACALLBACK_t pragmaCallback; + void *pragmaParam; + +#if AS_PROCESS_METADATA == 1 + int ExtractMetadata(int pos, std::vector &outMetadata); + int ExtractDeclaration(int pos, std::string &outName, std::string &outDeclaration, int &outType); + + enum METADATATYPE + { + MDT_TYPE = 1, + MDT_FUNC = 2, + MDT_VAR = 3, + MDT_VIRTPROP = 4, + MDT_FUNC_OR_VAR = 5 + }; + + // Temporary structure for storing metadata and declaration + struct SMetadataDecl + { + SMetadataDecl(std::vector m, std::string n, std::string d, int t, std::string c, std::string ns) : metadata(m), name(n), declaration(d), type(t), parentClass(c), nameSpace(ns) {} + std::vector metadata; + std::string name; + std::string declaration; + int type; + std::string parentClass; + std::string nameSpace; + }; + std::vector foundDeclarations; + std::string currentClass; + std::string currentNamespace; + + // Storage of metadata for global declarations + std::map > typeMetadataMap; + std::map > funcMetadataMap; + std::map > varMetadataMap; + + // Storage of metadata for class member declarations + struct SClassMetadata + { + SClassMetadata(const std::string& aName) : className(aName) {} + std::string className; + std::map > funcMetadataMap; + std::map > varMetadataMap; + }; + std::map classMetadataMap; + +#endif + +#ifdef _WIN32 + // On Windows the filenames are case insensitive so the comparisons to + // avoid duplicate includes must also be case insensitive. True case insensitive + // is not easy as it must be language aware, but a simple implementation such + // as strcmpi should suffice in almost all cases. + // + // ref: http://www.gotw.ca/gotw/029.htm + // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx + // ref: http://site.icu-project.org/ + + // TODO: Strings by default are treated as UTF8 encoded. If the application choses to + // use a different encoding, the comparison algorithm should be adjusted as well + + struct ci_less + { + bool operator()(const std::string &a, const std::string &b) const + { + return _stricmp(a.c_str(), b.c_str()) < 0; + } + }; + std::set includedScripts; +#else + std::set includedScripts; +#endif + + std::set definedWords; +}; + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.cpp b/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.cpp new file mode 100644 index 0000000..23a49eb --- /dev/null +++ b/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.cpp @@ -0,0 +1,1299 @@ +#include +#include +#include "scriptdictionary.h" +#include "../scriptarray/scriptarray.h" + +BEGIN_AS_NAMESPACE + +using namespace std; + +//------------------------------------------------------------------------ +// Object types are cached as user data to avoid costly runtime lookups + +// We just define a number here that we assume nobody else is using for +// object type user data. The add-ons have reserved the numbers 1000 +// through 1999 for this purpose, so we should be fine. +const asPWORD DICTIONARY_CACHE = 1003; + +// This cache holds the object type of the dictionary type and array type +// so it isn't necessary to look this up each time the dictionary or array +// is created. +struct SDictionaryCache +{ + asITypeInfo *dictType; + asITypeInfo *arrayType; + asITypeInfo *keyType; + + // This is called from RegisterScriptDictionary + static void Setup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache == 0 ) + { + cache = new SDictionaryCache; + engine->SetUserData(cache, DICTIONARY_CACHE); + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + + cache->dictType = engine->GetTypeInfoByName("dictionary"); + cache->arrayType = engine->GetTypeInfoByDecl("array"); + cache->keyType = engine->GetTypeInfoByDecl("string"); + } + } + + // This is called from the engine when shutting down + static void Cleanup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache ) + delete cache; + } +}; + +//-------------------------------------------------------------------------- +// CScriptDictionary implementation + +CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine) +{ + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(engine); + return obj; +} + +CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer) +{ + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(buffer); + return obj; +} + +CScriptDictionary::CScriptDictionary(asIScriptEngine *engine) +{ + Init(engine); +} + +void CScriptDictionary::Init(asIScriptEngine *e) +{ + // We start with one reference + refCount = 1; + gcFlag = false; + + // Keep a reference to the engine for as long as we live + // We don't increment the reference counter, because the + // engine will hold a pointer to the object in the GC. + engine = e; + + // The dictionary object type is cached to avoid dynamically parsing it each time + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); +} + +CScriptDictionary::CScriptDictionary(asBYTE *buffer) +{ + // This constructor will always be called from a script + // so we can get the engine from the active context + asIScriptContext *ctx = asGetActiveContext(); + Init(ctx->GetEngine()); + + // Determine if the dictionary key type is registered as reference type or value type + SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; + + // Initialize the dictionary from the buffer + asUINT length = *(asUINT*)buffer; + buffer += 4; + + while( length-- ) + { + // Align the buffer pointer on a 4 byte boundary in + // case previous value was smaller than 4 bytes + if( asPWORD(buffer) & 0x3 ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Get the name value pair from the buffer and insert it in the dictionary + dictKey_t name; + if (keyAsRef) + { + name = **(dictKey_t**)buffer; + buffer += sizeof(dictKey_t*); + } + else + { + name = *(dictKey_t*)buffer; + buffer += sizeof(dictKey_t); + } + + // Get the type id of the value + int typeId = *(int*)buffer; + buffer += sizeof(int); + + // Depending on the type id, the value will inline in the buffer or a pointer + void *ref = (void*)buffer; + + if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) + { + // Convert primitive values to either int64 or double, so we can use the overloaded Set methods + asINT64 i64; + double d; + switch( typeId ) + { + case asTYPEID_INT8: i64 = *(char*) ref; break; + case asTYPEID_INT16: i64 = *(short*) ref; break; + case asTYPEID_INT32: i64 = *(int*) ref; break; + case asTYPEID_INT64: i64 = *(asINT64*) ref; break; + case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; + case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; + case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; + case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; + case asTYPEID_FLOAT: d = *(float*) ref; break; + case asTYPEID_DOUBLE: d = *(double*) ref; break; + } + + if( typeId >= asTYPEID_FLOAT ) + Set(name, d); + else + Set(name, i64); + } + else + { + if( (typeId & asTYPEID_MASK_OBJECT) && + !(typeId & asTYPEID_OBJHANDLE) && + (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) + { + // Dereference the pointer to get the reference to the actual object + ref = *(void**)ref; + } + + Set(name, ref, typeId); + } + + // Advance the buffer pointer with the size of the value + if( typeId & asTYPEID_MASK_OBJECT ) + { + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti->GetFlags() & asOBJ_VALUE ) + buffer += ti->GetSize(); + else + buffer += sizeof(void*); + } + else if( typeId == 0 ) + { + // null pointer + buffer += sizeof(void*); + } + else + { + buffer += engine->GetSizeOfPrimitiveType(typeId); + } + } +} + +CScriptDictionary::~CScriptDictionary() +{ + // Delete all keys and values + DeleteAll(); +} + +void CScriptDictionary::AddRef() const +{ + // We need to clear the GC flag + gcFlag = false; + asAtomicInc(refCount); +} + +void CScriptDictionary::Release() const +{ + // We need to clear the GC flag + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + this->~CScriptDictionary(); + asFreeMem(const_cast(this)); + } +} + +int CScriptDictionary::GetRefCount() +{ + return refCount; +} + +void CScriptDictionary::SetGCFlag() +{ + gcFlag = true; +} + +bool CScriptDictionary::GetGCFlag() +{ + return gcFlag; +} + +void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine) +{ + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the dictionary is modified + + // Call the gc enum callback for each of the objects + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + if (it->second.m_typeId & asTYPEID_MASK_OBJECT) + { + asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); + if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); + } + else + { + // For others, simply notify the GC about the reference + inEngine->GCEnumCallback(it->second.m_valueObj); + } + } + } +} + +void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/) +{ + // We're being told to release all references in + // order to break circular references for dead objects + DeleteAll(); +} + +CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other) +{ + // Clear everything we had before + DeleteAll(); + + // Do a shallow copy of the dictionary + dictMap_t::const_iterator it; + for( it = other.dict.begin(); it != other.dict.end(); it++ ) + { + if( it->second.m_typeId & asTYPEID_OBJHANDLE ) + Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); + else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) + Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); + else + Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); + } + + return *this; +} + +CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) +{ + // Return the existing value if it exists, else insert an empty value + return &dict[key]; +} + +const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const +{ + // Return the existing value if it exists + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return &it->second; + + // Else raise an exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Invalid access to non-existing value"); + + return 0; +} + +void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId) +{ + dictMap_t::iterator it; + it = dict.find(key); + if( it == dict.end() ) + it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; + + it->second.Set(engine, value, typeId); +} + +// This overloaded method is implemented so that all integer and +// unsigned integers types will be stored in the dictionary as int64 +// through implicit conversions. This simplifies the management of the +// numeric types when the script retrieves the stored value using a +// different type. +void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value) +{ + Set(key, const_cast(&value), asTYPEID_INT64); +} + +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script +// retrieves the stored value using a different type. +void CScriptDictionary::Set(const dictKey_t &key, const double &value) +{ + Set(key, const_cast(&value), asTYPEID_DOUBLE); +} + +// Returns true if the value was successfully retrieved +bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.Get(engine, value, typeId); + + // AngelScript has already initialized the value with a default value, + // so we don't have to do anything if we don't find the element, or if + // the element is incompatible with the requested type. + + return false; +} + +// Returns the type id of the stored value +int CScriptDictionary::GetTypeId(const dictKey_t &key) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.m_typeId; + + return -1; +} + +bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const +{ + return Get(key, &value, asTYPEID_INT64); +} + +bool CScriptDictionary::Get(const dictKey_t &key, double &value) const +{ + return Get(key, &value, asTYPEID_DOUBLE); +} + +bool CScriptDictionary::Exists(const dictKey_t &key) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return true; + + return false; +} + +bool CScriptDictionary::IsEmpty() const +{ + if( dict.size() == 0 ) + return true; + + return false; +} + +asUINT CScriptDictionary::GetSize() const +{ + return asUINT(dict.size()); +} + +bool CScriptDictionary::Delete(const dictKey_t &key) +{ + dictMap_t::iterator it; + it = dict.find(key); + if( it != dict.end() ) + { + it->second.FreeValue(engine); + dict.erase(it); + return true; + } + + return false; +} + +void CScriptDictionary::DeleteAll() +{ + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + it->second.FreeValue(engine); + + dict.clear(); +} + +CScriptArray* CScriptDictionary::GetKeys() const +{ + // Retrieve the object type for the array from the cache + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + asITypeInfo *ti = cache->arrayType; + + // Create the array object + CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); + long current = -1; + dictMap_t::const_iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + current++; + *(dictKey_t*)array->At(current) = it->first; + } + + return array; +} + +//-------------------------------------------------------------------------- +// Generic wrappers + +void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen) +{ + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); +} + +void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen) +{ + asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); +} + +void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->AddRef(); +} + +void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->Release(); +} + +void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); + *dict = *other; + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; +} + +void ScriptDictionarySet_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + dict->Set(*key, ref, typeId); +} + +void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(asINT64*)ref); +} + +void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(double*)ref); +} + +void ScriptDictionaryGet_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); +} + +void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); +} + +void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); +} + +void ScriptDictionaryExists_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + bool ret = dict->Exists(*key); + *(bool*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + bool ret = dict->IsEmpty(); + *(bool*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + asUINT ret = dict->GetSize(); + *(asUINT*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); +} + +void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->DeleteAll(); +} + +static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); +} + +static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + self->SetGCFlag(); +} + +static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); +} + +static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllReferences(engine); +} + +static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); +} + +static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); +} + +static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) +{ + const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); +} + + +//------------------------------------------------------------------------- +// CScriptDictValue + +CScriptDictValue::CScriptDictValue() +{ + m_valueObj = 0; + m_typeId = 0; +} + +CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId) +{ + m_valueObj = 0; + m_typeId = 0; + Set(engine, value, typeId); +} + +CScriptDictValue::~CScriptDictValue() +{ + if (m_valueObj && m_typeId) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + FreeValue(ctx->GetEngine()); + else + { + // Must not hold an object when destroyed, as then the object will never be freed + assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); + } + } +} + +void CScriptDictValue::FreeValue(asIScriptEngine *engine) +{ + // If it is a handle or a ref counted object, call release + if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // Let the engine release the object + engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); + m_valueObj = 0; + m_typeId = 0; + } + + // For primitives, there's nothing to do +} + +void CScriptDictValue::EnumReferences(asIScriptEngine *inEngine) +{ + // If we're holding a reference, we'll notify the garbage collector of it + if (m_valueObj) + inEngine->GCEnumCallback(m_valueObj); + + // The object type itself is also garbage collected + if (m_typeId) + inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); +} + +void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId) +{ + FreeValue(engine); + + m_typeId = typeId; + if( typeId & asTYPEID_OBJHANDLE ) + { + // We're receiving a reference to the handle, so we need to dereference it + m_valueObj = *(void**)value; + engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); + if( m_valueObj == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Cannot create copy of object"); + } + } + else + { + // Copy the primitive value + // We receive a pointer to the value. + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(&m_valueInt, value, size); + } +} + +void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value) +{ + if( value.m_typeId & asTYPEID_OBJHANDLE ) + Set(engine, (void*)&value.m_valueObj, value.m_typeId); + else if( value.m_typeId & asTYPEID_MASK_OBJECT ) + Set(engine, (void*)value.m_valueObj, value.m_typeId); + else + Set(engine, (void*)&value.m_valueInt, value.m_typeId); +} + +// This overloaded method is implemented so that all integer and +// unsigned integers types will be stored in the dictionary as int64 +// through implicit conversions. This simplifies the management of the +// numeric types when the script retrieves the stored value using a +// different type. +void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value) +{ + Set(engine, const_cast(&value), asTYPEID_INT64); +} + +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script +// retrieves the stored value using a different type. +void CScriptDictValue::Set(asIScriptEngine *engine, const double &value) +{ + Set(engine, const_cast(&value), asTYPEID_DOUBLE); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const +{ + // Return the value + if( typeId & asTYPEID_OBJHANDLE ) + { + // A handle can be retrieved if the stored type is a handle of same or compatible type + // or if the stored type is an object that implements the interface that the handle refer to. + if( (m_typeId & asTYPEID_MASK_OBJECT) ) + { + // Don't allow the get if the stored handle is to a const, but the desired handle is not + if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) + return false; + + // RefCastObject will increment the refcount if successful + engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); + + return true; + } + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Verify that the copy can be made + bool isCompatible = false; + + // Allow a handle to be value assigned if the wanted type is not a handle + if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) + isCompatible = true; + + // Copy the object into the given reference + if( isCompatible ) + { + engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); + + return true; + } + } + else + { + if( m_typeId == typeId ) + { + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(value, &m_valueInt, size); + return true; + } + + // We know all numbers are stored as either int64 or double, since we register overloaded functions for those + // Only bool and enums needs to be treated separately + if( typeId == asTYPEID_DOUBLE ) + { + if( m_typeId == asTYPEID_INT64 ) + *(double*)value = double(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(double*)value = localValue ? 1.0 : 0.0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(double*)value = double(localValue); // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(double*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_INT64 ) + { + if( m_typeId == asTYPEID_DOUBLE ) + *(asINT64*)value = asINT64(m_valueFlt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(asINT64*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(asINT64*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(asINT64*)value = 0; + return false; + } + return true; + } + else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) + { + // The desired type is an enum. These are always 32bit integers + if( m_typeId == asTYPEID_DOUBLE ) + *(int*)value = int(m_valueFlt); + else if( m_typeId == asTYPEID_INT64 ) + *(int*)value = int(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(int*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(int*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(int*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_BOOL ) + { + if (m_typeId & asTYPEID_OBJHANDLE) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = m_valueObj ? true : false; + } + else if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = true; + } + else + { + // Compare only the bytes that were actually set + asQWORD zero = 0; + int size = engine->GetSizeOfPrimitiveType(m_typeId); + *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; + } + return true; + } + } + + // It was not possible to retrieve the value using the desired typeId + return false; +} + +const void * CScriptDictValue::GetAddressOfValue() const +{ + if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) + { + // Return the address to the object directly + return m_valueObj; + } + + // Return the address of the primitive or the pointer to the object + return reinterpret_cast(&m_valueObj); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const +{ + return Get(engine, &value, asTYPEID_INT64); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const +{ + return Get(engine, &value, asTYPEID_DOUBLE); +} + +int CScriptDictValue::GetTypeId() const +{ + return m_typeId; +} + +static void CScriptDictValue_Construct(void *mem) +{ + new(mem) CScriptDictValue(); +} + +static void CScriptDictValue_Destruct(CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->FreeValue(engine); + } + obj->~CScriptDictValue(); +} + +static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, ref, typeId); + } + return *obj; +} + +static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, const_cast(other)); + } + + return *obj; +} + +static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj) +{ + return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); +} + +static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj) +{ + return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); +} + +static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Get(engine, ref, typeId); + } +} + +static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj) +{ + asINT64 value; + CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); + return value; +} + +static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) +{ + double value; + CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); + return value; +} + +//------------------------------------------------------------------- +// generic wrapper for CScriptDictValue + +static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + double value; + self->Get(gen->GetEngine(), value); + *(double*)gen->GetAddressOfReturnLocation() = value; +} + +static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + asINT64 value; + self->Get(gen->GetEngine(), value); + *(asINT64*)gen->GetAddressOfReturnLocation() = value; +} + +static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); +} + +static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); +} + +static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); +} + +static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); +} + +static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); +} + +static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Construct(self); +} + +static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Destruct(self); +} + +static void CScriptDictValue_EnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->EnumReferences(gen->GetEngine()); +} + +static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->FreeValue(gen->GetEngine()); +} + +//-------------------------------------------------------------------------- +// Register the type + +void RegisterScriptDictionary(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptDictionary_Generic(engine); + else + RegisterScriptDictionary_Native(engine); +} + +void RegisterScriptDictionary_Native(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + + // The array type must be available + assert( engine->GetTypeInfoByDecl("array") ); + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); + +#if AS_USE_STLNAMES == 1 + // Same as isEmpty + r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as getSize + r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as delete + r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + // Same as deleteAll + r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); +#endif + + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); +} + +void RegisterScriptDictionary_Generic(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + + // Register the cleanup callback for the object type cache + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); +} + +//------------------------------------------------------------------ +// Iterator implementation + +CScriptDictionary::CIterator CScriptDictionary::begin() const +{ + return CIterator(*this, dict.begin()); +} + +CScriptDictionary::CIterator CScriptDictionary::end() const +{ + return CIterator(*this, dict.end()); +} + +CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const +{ + return CIterator(*this, dict.find(key)); +} + +CScriptDictionary::CIterator::CIterator( + const CScriptDictionary &dict, + dictMap_t::const_iterator it) + : m_it(it), m_dict(dict) +{} + +void CScriptDictionary::CIterator::operator++() +{ + ++m_it; +} + +void CScriptDictionary::CIterator::operator++(int) +{ + ++m_it; + + // Normally the post increment would return a copy of the object with the original state, + // but it is rarely used so we skip this extra copy to avoid unnecessary overhead +} + +CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*() +{ + return *this; +} + +bool CScriptDictionary::CIterator::operator==(const CIterator &other) const +{ + return m_it == other.m_it; +} + +bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const +{ + return m_it != other.m_it; +} + +const dictKey_t &CScriptDictionary::CIterator::GetKey() const +{ + return m_it->first; +} + +int CScriptDictionary::CIterator::GetTypeId() const +{ + return m_it->second.m_typeId; +} + +bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); +} + +bool CScriptDictionary::CIterator::GetValue(double &value) const +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); +} + +bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const +{ + return m_it->second.Get(m_dict.engine, value, typeId); +} + +const void *CScriptDictionary::CIterator::GetAddressOfValue() const +{ + return m_it->second.GetAddressOfValue(); +} + +END_AS_NAMESPACE + + diff --git a/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.h b/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.h new file mode 100644 index 0000000..062bb15 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptdictionary/scriptdictionary.h @@ -0,0 +1,240 @@ +#ifndef SCRIPTDICTIONARY_H +#define SCRIPTDICTIONARY_H + +// The dictionary class relies on the script string object, thus the script +// string type must be registered with the engine before registering the +// dictionary type + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +// By default the CScriptDictionary use the std::string for the keys. +// If the application uses a custom string type, then this typedef +// can be changed accordingly. +#include +typedef std::string dictKey_t; + +// Forward declare CScriptDictValue so we can typedef the internal map type +BEGIN_AS_NAMESPACE +class CScriptDictValue; +END_AS_NAMESPACE + +// C++11 introduced the std::unordered_map which is a hash map which is +// is generally more performatic for lookups than the std::map which is a +// binary tree. +// TODO: memory: The map allocator should use the asAllocMem and asFreeMem +#if AS_CAN_USE_CPP11 +#include +typedef std::unordered_map dictMap_t; +#else +#include +typedef std::map dictMap_t; +#endif + + +#ifdef _MSC_VER +// Turn off annoying warnings about truncated symbol names +#pragma warning (disable:4786) +#endif + + + + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on + +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptArray; +class CScriptDictionary; + +class CScriptDictValue +{ +public: + // This class must not be declared as local variable in C++, because it needs + // to receive the script engine pointer in all operations. The engine pointer + // is not kept as member in order to keep the size down + CScriptDictValue(); + CScriptDictValue(asIScriptEngine *engine, void *value, int typeId); + + // Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur + ~CScriptDictValue(); + + // Replace the stored value + void Set(asIScriptEngine *engine, void *value, int typeId); + void Set(asIScriptEngine *engine, const asINT64 &value); + void Set(asIScriptEngine *engine, const double &value); + void Set(asIScriptEngine *engine, CScriptDictValue &value); + + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(asIScriptEngine *engine, void *value, int typeId) const; + bool Get(asIScriptEngine *engine, asINT64 &value) const; + bool Get(asIScriptEngine *engine, double &value) const; + + // Returns the address of the stored value for inspection + const void *GetAddressOfValue() const; + + // Returns the type id of the stored value + int GetTypeId() const; + + // Free the stored value + void FreeValue(asIScriptEngine *engine); + + // GC callback + void EnumReferences(asIScriptEngine *engine); + +protected: + friend class CScriptDictionary; + + union + { + asINT64 m_valueInt; + double m_valueFlt; + void *m_valueObj; + }; + int m_typeId; +}; + +class CScriptDictionary +{ +public: + // Factory functions + static CScriptDictionary *Create(asIScriptEngine *engine); + + // Called from the script to instantiate a dictionary from an initialization list + static CScriptDictionary *Create(asBYTE *buffer); + + // Reference counting + void AddRef() const; + void Release() const; + + // Reassign the dictionary + CScriptDictionary &operator =(const CScriptDictionary &other); + + // Sets a key/value pair + void Set(const dictKey_t &key, void *value, int typeId); + void Set(const dictKey_t &key, const asINT64 &value); + void Set(const dictKey_t &key, const double &value); + + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(const dictKey_t &key, void *value, int typeId) const; + bool Get(const dictKey_t &key, asINT64 &value) const; + bool Get(const dictKey_t &key, double &value) const; + + // Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist + // If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned + CScriptDictValue *operator[](const dictKey_t &key); + const CScriptDictValue *operator[](const dictKey_t &key) const; + + // Returns the type id of the stored value, or negative if it doesn't exist + int GetTypeId(const dictKey_t &key) const; + + // Returns true if the key is set + bool Exists(const dictKey_t &key) const; + + // Returns true if there are no key/value pairs in the dictionary + bool IsEmpty() const; + + // Returns the number of key/value pairs in the dictionary + asUINT GetSize() const; + + // Deletes the key + bool Delete(const dictKey_t &key); + + // Deletes all keys + void DeleteAll(); + + // Get an array of all keys + CScriptArray *GetKeys() const; + + // STL style iterator + class CIterator + { + public: + void operator++(); // Pre-increment + void operator++(int); // Post-increment + + // This is needed to support C++11 range-for + CIterator &operator*(); + + bool operator==(const CIterator &other) const; + bool operator!=(const CIterator &other) const; + + // Accessors + const dictKey_t &GetKey() const; + int GetTypeId() const; + bool GetValue(asINT64 &value) const; + bool GetValue(double &value) const; + bool GetValue(void *value, int typeId) const; + const void * GetAddressOfValue() const; + + protected: + friend class CScriptDictionary; + + CIterator(); + CIterator(const CScriptDictionary &dict, + dictMap_t::const_iterator it); + + CIterator &operator=(const CIterator &) {return *this;} // Not used + + dictMap_t::const_iterator m_it; + const CScriptDictionary &m_dict; + }; + + CIterator begin() const; + CIterator end() const; + CIterator find(const dictKey_t &key) const; + + // Garbage collections behaviours + int GetRefCount(); + void SetGCFlag(); + bool GetGCFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllReferences(asIScriptEngine *engine); + +protected: + // Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory + // the constructors are made protected so that the application cannot allocate it + // manually in a different way + CScriptDictionary(asIScriptEngine *engine); + CScriptDictionary(asBYTE *buffer); + + // We don't want anyone to call the destructor directly, it should be called through the Release method + virtual ~CScriptDictionary(); + + // Cache the object types needed + void Init(asIScriptEngine *engine); + + // Our properties + asIScriptEngine *engine; + mutable int refCount; + mutable bool gcFlag; + dictMap_t dict; +}; + +// This function will determine the configuration of the engine +// and use one of the two functions below to register the dictionary object +void RegisterScriptDictionary(asIScriptEngine *engine); + +// Call this function to register the math functions +// using native calling conventions +void RegisterScriptDictionary_Native(asIScriptEngine *engine); + +// Use this one instead if native calling conventions +// are not supported on the target platform +void RegisterScriptDictionary_Generic(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scripthandle/scripthandle.cpp b/TestRunner/angelscript_addons/scripthandle/scripthandle.cpp new file mode 100644 index 0000000..e47b1fe --- /dev/null +++ b/TestRunner/angelscript_addons/scripthandle/scripthandle.cpp @@ -0,0 +1,360 @@ +#include "scripthandle.h" +#include +#include +#include + +BEGIN_AS_NAMESPACE + +static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); } +static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); } +// This one is not static because it needs to be friend with the CScriptHandle class +void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); } +static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); } + +CScriptHandle::CScriptHandle() +{ + m_ref = 0; + m_type = 0; +} + +CScriptHandle::CScriptHandle(const CScriptHandle &other) +{ + m_ref = other.m_ref; + m_type = other.m_type; + + AddRefHandle(); +} + +CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type) +{ + m_ref = ref; + m_type = type; + + AddRefHandle(); +} + +// This constructor shouldn't be called from the application +// directly as it requires an active script context +CScriptHandle::CScriptHandle(void *ref, int typeId) +{ + m_ref = 0; + m_type = 0; + + Assign(ref, typeId); +} + +CScriptHandle::~CScriptHandle() +{ + ReleaseHandle(); +} + +void CScriptHandle::ReleaseHandle() +{ + if( m_ref && m_type ) + { + asIScriptEngine *engine = m_type->GetEngine(); + engine->ReleaseScriptObject(m_ref, m_type); + + engine->Release(); + + m_ref = 0; + m_type = 0; + } +} + +void CScriptHandle::AddRefHandle() +{ + if( m_ref && m_type ) + { + asIScriptEngine *engine = m_type->GetEngine(); + engine->AddRefScriptObject(m_ref, m_type); + + // Hold on to the engine so it isn't destroyed while + // a reference to a script object is still held + engine->AddRef(); + } +} + +CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other) +{ + Set(other.m_ref, other.m_type); + + return *this; +} + +void CScriptHandle::Set(void *ref, asITypeInfo *type) +{ + if( m_ref == ref ) return; + + ReleaseHandle(); + + m_ref = ref; + m_type = type; + + AddRefHandle(); +} + +void *CScriptHandle::GetRef() +{ + return m_ref; +} + +asITypeInfo *CScriptHandle::GetType() const +{ + return m_type; +} + +int CScriptHandle::GetTypeId() const +{ + if( m_type == 0 ) return 0; + + return m_type->GetTypeId() | asTYPEID_OBJHANDLE; +} + +// This method shouldn't be called from the application +// directly as it requires an active script context +CScriptHandle &CScriptHandle::Assign(void *ref, int typeId) +{ + // When receiving a null handle we just clear our memory + if( typeId == 0 ) + { + Set(0, 0); + return *this; + } + + // Dereference received handles to get the object + if( typeId & asTYPEID_OBJHANDLE ) + { + // Store the actual reference + ref = *(void**)ref; + typeId &= ~asTYPEID_OBJHANDLE; + } + + // Get the object type + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(typeId); + + // If the argument is another CScriptHandle, we should copy the content instead + if( type && strcmp(type->GetName(), "ref") == 0 ) + { + CScriptHandle *r = (CScriptHandle*)ref; + ref = r->m_ref; + type = r->m_type; + } + + Set(ref, type); + + return *this; +} + +bool CScriptHandle::operator==(const CScriptHandle &o) const +{ + if( m_ref == o.m_ref && + m_type == o.m_type ) + return true; + + // TODO: If type is not the same, we should attempt to do a dynamic cast, + // which may change the pointer for application registered classes + + return false; +} + +bool CScriptHandle::operator!=(const CScriptHandle &o) const +{ + return !(*this == o); +} + +bool CScriptHandle::Equals(void *ref, int typeId) const +{ + // Null handles are received as reference to a null handle + if( typeId == 0 ) + ref = 0; + + // Dereference handles to get the object + if( typeId & asTYPEID_OBJHANDLE ) + { + // Compare the actual reference + ref = *(void**)ref; + typeId &= ~asTYPEID_OBJHANDLE; + } + + // TODO: If typeId is not the same, we should attempt to do a dynamic cast, + // which may change the pointer for application registered classes + + if( ref == m_ref ) return true; + + return false; +} + +// AngelScript: used as '@obj = cast(ref);' +void CScriptHandle::Cast(void **outRef, int typeId) +{ + // If we hold a null handle, then just return null + if( m_type == 0 ) + { + *outRef = 0; + return; + } + + // It is expected that the outRef is always a handle + assert( typeId & asTYPEID_OBJHANDLE ); + + // Compare the type id of the actual object + typeId &= ~asTYPEID_OBJHANDLE; + asIScriptEngine *engine = m_type->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(typeId); + + *outRef = 0; + + // RefCastObject will increment the refCount of the returned object if successful + engine->RefCastObject(m_ref, m_type, type, outRef); +} + +void CScriptHandle::EnumReferences(asIScriptEngine *inEngine) +{ + // If we're holding a reference, we'll notify the garbage collector of it + if (m_ref) + inEngine->GCEnumCallback(m_ref); + + // The object type itself is also garbage collected + if( m_type) + inEngine->GCEnumCallback(m_type); +} + +void CScriptHandle::ReleaseReferences(asIScriptEngine *) +{ + // Simply clear the content to release the references + Set(0, 0); +} + +void RegisterScriptHandle_Native(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 ); +} + +void CScriptHandle_Construct_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + new(self) CScriptHandle(); +} + +void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + new(self) CScriptHandle(*other); +} + +void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + Construct(self, ref, typeId); +} + +void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->~CScriptHandle(); +} + +void CScriptHandle_Cast_Generic(asIScriptGeneric *gen) +{ + void **ref = reinterpret_cast(gen->GetArgAddress(0)); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->Cast(ref, typeId); +} + +void CScriptHandle_Assign_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + *self = *other; + gen->SetReturnAddress(self); +} + +void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->Assign(ref, typeId); + gen->SetReturnAddress(self); +} + +void CScriptHandle_Equals_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(*self == *other); +} + +void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(self->Equals(ref, typeId)); +} + +void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->EnumReferences(gen->GetEngine()); +} + +void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->ReleaseReferences(gen->GetEngine()); +} + +void RegisterScriptHandle_Generic(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + +void RegisterScriptHandle(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptHandle_Generic(engine); + else + RegisterScriptHandle_Native(engine); +} + + +END_AS_NAMESPACE diff --git a/TestRunner/angelscript_addons/scripthandle/scripthandle.h b/TestRunner/angelscript_addons/scripthandle/scripthandle.h new file mode 100644 index 0000000..7adf1b7 --- /dev/null +++ b/TestRunner/angelscript_addons/scripthandle/scripthandle.h @@ -0,0 +1,69 @@ +#ifndef SCRIPTHANDLE_H +#define SCRIPTHANDLE_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptHandle +{ +public: + // Constructors + CScriptHandle(); + CScriptHandle(const CScriptHandle &other); + CScriptHandle(void *ref, asITypeInfo *type); + ~CScriptHandle(); + + // Copy the stored value from another any object + CScriptHandle &operator=(const CScriptHandle &other); + + // Set the reference + void Set(void *ref, asITypeInfo *type); + + // Compare equalness + bool operator==(const CScriptHandle &o) const; + bool operator!=(const CScriptHandle &o) const; + bool Equals(void *ref, int typeId) const; + + // Dynamic cast to desired handle type + void Cast(void **outRef, int typeId); + + // Returns the type of the reference held + asITypeInfo *GetType() const; + int GetTypeId() const; + + // Get the reference + void *GetRef(); + + // GC callback + void EnumReferences(asIScriptEngine *engine); + void ReleaseReferences(asIScriptEngine *engine); + +protected: + // These functions need to have access to protected + // members in order to call them from the script engine + friend void Construct(CScriptHandle *self, void *ref, int typeId); + friend void RegisterScriptHandle_Native(asIScriptEngine *engine); + friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen); + + void ReleaseHandle(); + void AddRefHandle(); + + // These shouldn't be called directly by the + // application as they requires an active context + CScriptHandle(void *ref, int typeId); + CScriptHandle &Assign(void *ref, int typeId); + + void *m_ref; + asITypeInfo *m_type; +}; + +void RegisterScriptHandle(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scripthelper/scripthelper.cpp b/TestRunner/angelscript_addons/scripthelper/scripthelper.cpp new file mode 100644 index 0000000..bb85b65 --- /dev/null +++ b/TestRunner/angelscript_addons/scripthelper/scripthelper.cpp @@ -0,0 +1,987 @@ +#include +#include "scripthelper.h" +#include +#include +#include +#include +#include + +using namespace std; + +BEGIN_AS_NAMESPACE + +int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result) +{ + // TODO: If a lot of script objects are going to be compared, e.g. when sorting an array, + // then the method id and context should be cached between calls. + + int retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opCmp method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->GetMethodByIndex(n); + asDWORD flags; + if( strcmp(f->GetName(), "opCmp") == 0 && + f->GetReturnTypeId(&flags) == asTYPEID_INT32 && + flags == asTM_NONE && + f->GetParamCount() == 1 ) + { + int paramTypeId; + f->GetParam(0, ¶mTypeId, &flags); + + // The parameter must be an input reference of the same type + // If the reference is a inout reference, then it must also be read-only + if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) + break; + + // Found the method + func = f; + break; + } + } + } + + if( func ) + { + // Call the method + asIScriptContext *ctx = engine->CreateContext(); + ctx->Prepare(func); + ctx->SetObject(lobj); + ctx->SetArgAddress(0, robj); + int r = ctx->Execute(); + if( r == asEXECUTION_FINISHED ) + { + result = (int)ctx->GetReturnDWord(); + + // The comparison was successful + retval = 0; + } + ctx->Release(); + } + + return retval; +} + +int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result) +{ + // TODO: If a lot of script objects are going to be compared, e.g. when searching for an + // entry in a set, then the method and context should be cached between calls. + + int retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opEquals method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->GetMethodByIndex(n); + asDWORD flags; + if( strcmp(f->GetName(), "opEquals") == 0 && + f->GetReturnTypeId(&flags) == asTYPEID_BOOL && + flags == asTM_NONE && + f->GetParamCount() == 1 ) + { + int paramTypeId; + f->GetParam(0, ¶mTypeId, &flags); + + // The parameter must be an input reference of the same type + // If the reference is a inout reference, then it must also be read-only + if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) + break; + + // Found the method + func = f; + break; + } + } + } + + if( func ) + { + // Call the method + asIScriptContext *ctx = engine->CreateContext(); + ctx->Prepare(func); + ctx->SetObject(lobj); + ctx->SetArgAddress(0, robj); + int r = ctx->Execute(); + if( r == asEXECUTION_FINISHED ) + { + result = ctx->GetReturnByte() ? true : false; + + // The comparison was successful + retval = 0; + } + ctx->Release(); + } + else + { + // If the opEquals method doesn't exist, then we try with opCmp instead + int relation; + retval = CompareRelation(engine, lobj, robj, typeId, relation); + if( retval >= 0 ) + result = relation == 0 ? true : false; + } + + return retval; +} + +int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod, asIScriptContext *ctx) +{ + return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx); +} + +int ExecuteString(asIScriptEngine *engine, const char *code, void *ref, int refTypeId, asIScriptModule *mod, asIScriptContext *ctx) +{ + // Wrap the code in a function so that it can be compiled and executed + string funcCode = " ExecuteString() {\n"; + funcCode += code; + funcCode += "\n;}"; + + // Determine the return type based on the type of the ref arg + funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode; + + // GetModule will free unused types, so to be on the safe side we'll hold on to a reference to the type + asITypeInfo *type = 0; + if( refTypeId & asTYPEID_MASK_OBJECT ) + { + type = engine->GetTypeInfoById(refTypeId); + if( type ) + type->AddRef(); + } + + // If no module was provided, get a dummy from the engine + asIScriptModule *execMod = mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE); + + // Now it's ok to release the type + if( type ) + type->Release(); + + // Compile the function that can be executed + asIScriptFunction *func = 0; + int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0, &func); + if( r < 0 ) + return r; + + // If no context was provided, request a new one from the engine + asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext(); + r = execCtx->Prepare(func); + if (r >= 0) + { + // Execute the function + r = execCtx->Execute(); + + // Unless the provided type was void retrieve it's value + if (ref != 0 && refTypeId != asTYPEID_VOID) + { + if (refTypeId & asTYPEID_OBJHANDLE) + { + // Expect the pointer to be null to start with + assert(*reinterpret_cast(ref) == 0); + *reinterpret_cast(ref) = *reinterpret_cast(execCtx->GetAddressOfReturnValue()); + engine->AddRefScriptObject(*reinterpret_cast(ref), engine->GetTypeInfoById(refTypeId)); + } + else if (refTypeId & asTYPEID_MASK_OBJECT) + { + // Use the registered assignment operator to do a value assign. + // This assumes that the ref is pointing to a valid object instance. + engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId)); + } + else + { + // Copy the primitive value + memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); + } + } + } + + // Clean up + func->Release(); + if( !ctx ) engine->ReturnContext(execCtx); + + return r; +} + +int WriteConfigToFile(asIScriptEngine *engine, const char *filename) +{ + ofstream strm; + strm.open(filename); + + return WriteConfigToStream(engine, strm); +} + +int WriteConfigToStream(asIScriptEngine *engine, ostream &strm) +{ + // A helper function for escaping quotes in default arguments + struct Escape + { + static string Quotes(const char *decl) + { + string str = decl; + size_t pos = 0; + for(;;) + { + // Find " characters + pos = str.find("\"",pos); + if( pos == string::npos ) + break; + + // Add a \ to escape them + str.insert(pos, "\\"); + pos += 2; + } + + return str; + } + }; + + int c, n; + + asDWORD currAccessMask = 0; + string currNamespace = ""; + engine->SetDefaultNamespace(""); + + // Export the engine version, just for info + strm << "// AngelScript " << asGetLibraryVersion() << "\n"; + strm << "// Lib options " << asGetLibraryOptions() << "\n"; + + // Export the relevant engine properties + strm << "// Engine properties\n"; + for( n = 0; n < asEP_LAST_PROPERTY; n++ ) + strm << "ep " << n << " " << engine->GetEngineProperty(asEEngineProp(n)) << "\n"; + + // Make sure the default array type is expanded to the template form + bool expandDefArrayToTempl = engine->GetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL) ? true : false; + engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true); + + // Write enum types and their values + strm << "\n// Enums\n"; + c = engine->GetEnumCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *ti = engine->GetEnumByIndex(n); + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + const char *enumName = ti->GetName(); + strm << "enum " << enumName << "\n"; + for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ ) + { + const char *valName; + int val; + valName = ti->GetEnumValueByIndex(m, &val); + strm << "enumval " << enumName << " " << valName << " " << val << "\n"; + } + } + + // Enumerate all types + strm << "\n// Types\n"; + + // Keep a list of the template types, as the methods for these need to be exported first + set templateTypes; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *type = engine->GetObjectTypeByIndex(n); + asDWORD accessMask = type->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + const char *nameSpace = type->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) + { + // This should only be interfaces + assert( type->GetSize() == 0 ); + + strm << "intf " << type->GetName() << "\n"; + } + else + { + // Only the type flags are necessary. The application flags are application + // specific and doesn't matter to the offline compiler. The object size is also + // unnecessary for the offline compiler + strm << "objtype \"" << engine->GetTypeDeclaration(type->GetTypeId()) << "\" " << (unsigned int)(type->GetFlags() & asOBJ_MASK_VALID_FLAGS) << "\n"; + + // Store the template types (but not template instances) + if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) ) + templateTypes.insert(type); + } + } + + c = engine->GetTypedefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *ti = engine->GetTypedefByIndex(n); + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n"; + } + + c = engine->GetFuncdefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *funcDef = engine->GetFuncdefByIndex(n); + asDWORD accessMask = funcDef->GetAccessMask(); + const char *nameSpace = funcDef->GetNamespace(); + // Child funcdefs do not have any namespace, as they belong to the parent object + if( nameSpace && nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n"; + } + + // A helper for writing object type members + struct TypeWriter + { + static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask) + { + const char *nameSpace = type->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + string typeDecl = engine->GetTypeDeclaration(type->GetTypeId()); + if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) + { + for( asUINT m = 0; m < type->GetMethodCount(); m++ ) + { + asIScriptFunction *func = type->GetMethodByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "intfmthd " << typeDecl.c_str() << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + } + else + { + asUINT m; + for( m = 0; m < type->GetFactoryCount(); m++ ) + { + asIScriptFunction *func = type->GetFactoryByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objbeh \"" << typeDecl.c_str() << "\" " << asBEHAVE_FACTORY << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + } + for( m = 0; m < type->GetBehaviourCount(); m++ ) + { + asEBehaviours beh; + asIScriptFunction *func = type->GetBehaviourByIndex(m, &beh); + + if( beh == asBEHAVE_CONSTRUCT ) + // Prefix 'void' + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + else if( beh == asBEHAVE_DESTRUCT ) + // Prefix 'void' and remove ~ + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str()+1 << "\"\n"; + else + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + } + for( m = 0; m < type->GetMethodCount(); m++ ) + { + asIScriptFunction *func = type->GetMethodByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objmthd \"" << typeDecl.c_str() << "\" \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + for( m = 0; m < type->GetPropertyCount(); m++ ) + { + asDWORD accessMask; + type->GetProperty(m, 0, 0, 0, 0, 0, 0, &accessMask); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objprop \"" << typeDecl.c_str() << "\" \"" << type->GetPropertyDeclaration(m) << "\""; + + // Save information about composite properties + int compositeOffset; + bool isCompositeIndirect; + type->GetProperty(m, 0, 0, 0, 0, 0, 0, 0, &compositeOffset, &isCompositeIndirect); + strm << " " << compositeOffset << " " << (isCompositeIndirect ? "1" : "0") << "\n"; + } + } + } + }; + + // Write the members of the template types, so they can be fully registered before any other type uses them + // TODO: Order the template types based on dependency to avoid failure if one type uses instances of another + strm << "\n// Template type members\n"; + for( set::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it ) + { + asITypeInfo *type = *it; + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // Write the object types members + strm << "\n// Type members\n"; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *type = engine->GetObjectTypeByIndex(n); + if( templateTypes.find(type) == templateTypes.end() ) + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // Write functions + strm << "\n// Functions\n"; + + c = engine->GetGlobalFunctionCount(); + for( n = 0; n < c; n++ ) + { + asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n); + const char *nameSpace = func->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "func \"" << Escape::Quotes(func->GetDeclaration()).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + + // Write global properties + strm << "\n// Properties\n"; + + c = engine->GetGlobalPropertyCount(); + for( n = 0; n < c; n++ ) + { + const char *name; + int typeId; + bool isConst; + asDWORD accessMask; + const char *nameSpace; + engine->GetGlobalPropertyByIndex(n, &name, &nameSpace, &typeId, &isConst, 0, 0, &accessMask); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; + } + + // Write string factory + strm << "\n// String factory\n"; + + // Reset the namespace for the string factory and default array type + if ("" != currNamespace) + { + strm << "namespace \"\"\n"; + currNamespace = ""; + engine->SetDefaultNamespace(""); + } + + asDWORD flags = 0; + int typeId = engine->GetStringFactoryReturnTypeId(&flags); + if( typeId > 0 ) + strm << "strfactory \"" << ((flags & asTM_CONST) ? "const " : "") << engine->GetTypeDeclaration(typeId) << ((flags & asTM_INOUTREF) ? "&" : "") << "\"\n"; + + // Write default array type + strm << "\n// Default array type\n"; + typeId = engine->GetDefaultArrayTypeId(); + if( typeId > 0 ) + strm << "defarray \"" << engine->GetTypeDeclaration(typeId) << "\"\n"; + + // Restore original settings + engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, expandDefArrayToTempl); + + return 0; +} + +int ConfigEngineFromStream(asIScriptEngine *engine, istream &strm, const char *configFile, asIStringFactory *stringFactory) +{ + int r; + + // Some helper functions for parsing the configuration + struct in + { + static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&text[pos], text.length() - pos, &len); + while( (t == asTC_WHITESPACE || t == asTC_COMMENT) && pos < text.length() ) + { + pos += len; + t = engine->ParseToken(&text[pos], text.length() - pos, &len); + } + + token.assign(&text[pos], len); + + pos += len; + + return t; + } + + static void ReplaceSlashQuote(string &str) + { + size_t pos = 0; + for(;;) + { + // Search for \" in the string + pos = str.find("\\\"", pos); + if( pos == string::npos ) + break; + + // Remove the \ character + str.erase(pos, 1); + } + } + + static asUINT GetLineNumber(const string &text, asUINT pos) + { + asUINT count = 1; + for( asUINT n = 0; n < pos; n++ ) + if( text[n] == '\n' ) + count++; + + return count; + } + }; + + // Since we are only going to compile the script and never actually execute it, + // we turn off the initialization of global variables, so that the compiler can + // just register dummy types and functions for the application interface. + r = engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); assert( r >= 0 ); + + // Read the entire file + char buffer[1000]; + string config; + do { + strm.getline(buffer, 1000); + config += buffer; + config += "\n"; + } while( !strm.eof() && strm.good() ); + + // Process the configuration file and register each entity + asUINT pos = 0; + while( pos < config.length() ) + { + string token; + // TODO: The position where the initial token is found should be stored for error messages + in::GetToken(engine, token, config, pos); + if( token == "ep" ) + { + string tmp; + in::GetToken(engine, tmp, config, pos); + + asEEngineProp ep = asEEngineProp(atol(tmp.c_str())); + + // Only set properties that affect the compiler + if( ep != asEP_COPY_SCRIPT_SECTIONS && + ep != asEP_MAX_STACK_SIZE && + ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD && + ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL && + ep != asEP_AUTO_GARBAGE_COLLECT ) + { + // Get the value for the property + in::GetToken(engine, tmp, config, pos); + stringstream s(tmp); + asPWORD value; + + s >> value; + + engine->SetEngineProperty(ep, value); + } + } + else if( token == "namespace" ) + { + string ns; + in::GetToken(engine, ns, config, pos); + ns = ns.substr(1, ns.length() - 2); + + r = engine->SetDefaultNamespace(ns.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to set namespace"); + return -1; + } + } + else if( token == "access" ) + { + string maskStr; + in::GetToken(engine, maskStr, config, pos); + asDWORD mask = strtoul(maskStr.c_str(), 0, 16); + engine->SetDefaultAccessMask(mask); + } + else if( token == "objtype" ) + { + string name, flags; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, flags, config, pos); + + // The size of the value type doesn't matter, because the + // engine must adjust it anyway for different platforms + r = engine->RegisterObjectType(name.c_str(), (atol(flags.c_str()) & asOBJ_VALUE) ? 1 : 0, atol(flags.c_str())); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object type"); + return -1; + } + } + else if( token == "objbeh" ) + { + string name, behaviour, decl; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, behaviour, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + // Remove the $ that the engine prefixes the behaviours with + size_t n = decl.find("$"); + if( n != string::npos ) + decl[n] = ' '; + + asEBehaviours behave = static_cast(atol(behaviour.c_str())); + if( behave == asBEHAVE_TEMPLATE_CALLBACK ) + { + // TODO: How can we let the compiler register this? Maybe through a plug-in system? Or maybe by implementing the callback as a script itself + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register template callback without the actual implementation"); + } + else + { + r = engine->RegisterObjectBehaviour(name.c_str(), behave, decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register behaviour"); + return -1; + } + } + } + else if( token == "objmthd" ) + { + string name, decl; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterObjectMethod(name.c_str(), decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object method"); + return -1; + } + } + else if( token == "objprop" ) + { + string name, decl, compositeOffset, isCompositeIndirect; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::GetToken(engine, compositeOffset, config, pos); + in::GetToken(engine, isCompositeIndirect, config, pos); + + asITypeInfo *type = engine->GetTypeInfoById(engine->GetTypeIdByDecl(name.c_str())); + if( type == 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Type doesn't exist for property registration"); + return -1; + } + + // All properties must have different offsets in order to make them + // distinct, so we simply register them with an incremental offset + r = engine->RegisterObjectProperty(name.c_str(), decl.c_str(), type->GetPropertyCount(), compositeOffset != "0" ? type->GetPropertyCount() : 0, isCompositeIndirect != "0"); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object property"); + return -1; + } + } + else if( token == "intf" ) + { + string name, size, flags; + in::GetToken(engine, name, config, pos); + + r = engine->RegisterInterface(name.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface"); + return -1; + } + } + else if( token == "intfmthd" ) + { + string name, decl; + in::GetToken(engine, name, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterInterfaceMethod(name.c_str(), decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface method"); + return -1; + } + } + else if( token == "func" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterGlobalFunction(decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global function"); + return -1; + } + } + else if( token == "prop" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + // All properties must have different offsets in order to make them + // distinct, so we simply register them with an incremental offset. + // The pointer must also be non-null so we add 1 to have a value. + r = engine->RegisterGlobalProperty(decl.c_str(), reinterpret_cast(asPWORD(engine->GetGlobalPropertyCount()+1))); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global property"); + return -1; + } + } + else if( token == "strfactory" ) + { + string type; + in::GetToken(engine, type, config, pos); + type = type.substr(1, type.length() - 2); + + if (stringFactory == 0) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register string factory without the actual implementation"); + return -1; + } + else + { + r = engine->RegisterStringFactory(type.c_str(), stringFactory); + if (r < 0) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register string factory"); + return -1; + } + } + } + else if( token == "defarray" ) + { + string type; + in::GetToken(engine, type, config, pos); + type = type.substr(1, type.length() - 2); + + r = engine->RegisterDefaultArrayType(type.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register the default array type"); + return -1; + } + } + else if( token == "enum" ) + { + string type; + in::GetToken(engine, type, config, pos); + + r = engine->RegisterEnum(type.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum type"); + return -1; + } + } + else if( token == "enumval" ) + { + string type, name, value; + in::GetToken(engine, type, config, pos); + in::GetToken(engine, name, config, pos); + in::GetToken(engine, value, config, pos); + + r = engine->RegisterEnumValue(type.c_str(), name.c_str(), atol(value.c_str())); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum value"); + return -1; + } + } + else if( token == "typedef" ) + { + string type, decl; + in::GetToken(engine, type, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + r = engine->RegisterTypedef(type.c_str(), decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register typedef"); + return -1; + } + } + else if( token == "funcdef" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + r = engine->RegisterFuncdef(decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register funcdef"); + return -1; + } + } + } + + return 0; +} + +string GetExceptionInfo(asIScriptContext *ctx, bool showStack) +{ + if( ctx->GetState() != asEXECUTION_EXCEPTION ) return ""; + + stringstream text; + + const asIScriptFunction *function = ctx->GetExceptionFunction(); + text << "func: " << function->GetDeclaration() << "\n"; + text << "modl: " << (function->GetModuleName() ? function->GetModuleName() : "") << "\n"; + text << "sect: " << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << "\n"; + text << "line: " << ctx->GetExceptionLineNumber() << "\n"; + text << "desc: " << ctx->GetExceptionString() << "\n"; + + if( showStack ) + { + text << "--- call stack ---\n"; + for( asUINT n = 1; n < ctx->GetCallstackSize(); n++ ) + { + function = ctx->GetFunction(n); + if( function ) + { + if( function->GetFuncType() == asFUNC_SCRIPT ) + { + text << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << " (" << ctx->GetLineNumber(n) << "): " << function->GetDeclaration() << "\n"; + } + else + { + // The context is being reused by the application for a nested call + text << "{...application...}: " << function->GetDeclaration() << "\n"; + } + } + else + { + // The context is being reused by the script engine for a nested call + text << "{...script engine...}\n"; + } + } + } + + return text.str(); +} + +void ScriptThrow(const string &msg) +{ + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException(msg.c_str()); +} + +string ScriptGetExceptionInfo() +{ + asIScriptContext *ctx = asGetActiveContext(); + if (!ctx) + return ""; + + const char *msg = ctx->GetExceptionString(); + if (msg == 0) + return ""; + + return string(msg); +} + +void RegisterExceptionRoutines(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + + // The string type must be available + assert(engine->GetTypeInfoByDecl("string")); + + r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); +} + +END_AS_NAMESPACE diff --git a/TestRunner/angelscript_addons/scripthelper/scripthelper.h b/TestRunner/angelscript_addons/scripthelper/scripthelper.h new file mode 100644 index 0000000..dc3e0b8 --- /dev/null +++ b/TestRunner/angelscript_addons/scripthelper/scripthelper.h @@ -0,0 +1,53 @@ +#ifndef SCRIPTHELPER_H +#define SCRIPTHELPER_H + +#include +#include + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +// Compare relation between two objects of the same type +int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result); + +// Compare equality between two objects of the same type +int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result); + +// Compile and execute simple statements +// The module is optional. If given the statements can access the entities compiled in the module. +// The caller can optionally provide its own context, for example if a context should be reused. +int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); + +// Compile and execute simple statements with option of return value +// The module is optional. If given the statements can access the entitites compiled in the module. +// The caller can optionally provide its own context, for example if a context should be reused. +int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retTypeId, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); + +// Write the registered application interface to a file for an offline compiler. +// The format is compatible with the offline compiler in /sdk/samples/asbuild/. +int WriteConfigToFile(asIScriptEngine *engine, const char *filename); + +// Write the registered application interface to a text stream. +int WriteConfigToStream(asIScriptEngine *engine, std::ostream &strm); + +// Loads an interface from a text stream and configures the engine with it. This will not +// set the correct function pointers, so it is not possible to use this engine to execute +// scripts, but it can be used to compile scripts and save the byte code. +int ConfigEngineFromStream(asIScriptEngine *engine, std::istream &strm, const char *nameOfStream = "config", asIStringFactory *stringFactory = 0); + +// Format the details of the script exception into a human readable text +std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false); + +// Register the exception routines +// 'void throw(const string &msg)' +// 'string getExceptionInfo()' +void RegisterExceptionRoutines(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.cpp b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.cpp new file mode 100644 index 0000000..2a96ad4 --- /dev/null +++ b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.cpp @@ -0,0 +1,1365 @@ +#include "scriptstdstring.h" +#include // assert() +#include // std::stringstream +#include // strstr() +#include // sprintf() +#include // strtod() +#ifndef __psp2__ + #include // setlocale() +#endif + +using namespace std; + +// This macro is used to avoid warnings about unused variables. +// Usually where the variables are only used in debug mode. +#define UNUSED_VAR(x) (void)(x) + +#ifdef AS_CAN_USE_CPP11 +// The string factory doesn't need to keep a specific order in the +// cache, so the unordered_map is faster than the ordinary map +#include // std::unordered_map +BEGIN_AS_NAMESPACE +typedef unordered_map map_t; +END_AS_NAMESPACE +#else +#include // std::map +BEGIN_AS_NAMESPACE +typedef map map_t; +END_AS_NAMESPACE +#endif + +BEGIN_AS_NAMESPACE +class CStdStringFactory : public asIStringFactory +{ +public: + CStdStringFactory() {} + ~CStdStringFactory() + { + // The script engine must release each string + // constant that it has requested + assert(stringCache.size() == 0); + } + + const void *GetStringConstant(const char *data, asUINT length) + { + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + string str(data, length); + map_t::iterator it = stringCache.find(str); + if (it != stringCache.end()) + it->second++; + else + it = stringCache.insert(map_t::value_type(str, 1)).first; + + asReleaseExclusiveLock(); + + return reinterpret_cast(&it->first); + } + + int ReleaseStringConstant(const void *str) + { + if (str == 0) + return asERROR; + + int ret = asSUCCESS; + + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + map_t::iterator it = stringCache.find(*reinterpret_cast(str)); + if (it == stringCache.end()) + ret = asERROR; + else + { + it->second--; + if (it->second == 0) + stringCache.erase(it); + } + + asReleaseExclusiveLock(); + + return ret; + } + + int GetRawStringData(const void *str, char *data, asUINT *length) const + { + if (str == 0) + return asERROR; + + if (length) + *length = (asUINT)reinterpret_cast(str)->length(); + + if (data) + memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); + + return asSUCCESS; + } + + // THe access to the string cache is protected with the common mutex provided by AngelScript + map_t stringCache; +}; + +static CStdStringFactory *stringFactory = 0; + +// TODO: Make this public so the application can also use the string +// factory and share the string constants if so desired, or to +// monitor the size of the string factory cache. +CStdStringFactory *GetStdStringFactorySingleton() +{ + if( stringFactory == 0 ) + { + // The following instance will be destroyed by the global + // CStdStringFactoryCleaner instance upon application shutdown + stringFactory = new CStdStringFactory(); + } + return stringFactory; +} + +class CStdStringFactoryCleaner +{ +public: + ~CStdStringFactoryCleaner() + { + if (stringFactory) + { + // Only delete the string factory if the stringCache is empty + // If it is not empty, it means that someone might still attempt + // to release string constants, so if we delete the string factory + // the application might crash. Not deleting the cache would + // lead to a memory leak, but since this is only happens when the + // application is shutting down anyway, it is not important. + if (stringFactory->stringCache.empty()) + { + delete stringFactory; + stringFactory = 0; + } + } + } +}; + +static CStdStringFactoryCleaner cleaner; + + +static void ConstructString(string *thisPointer) +{ + new(thisPointer) string(); +} + +static void CopyConstructString(const string &other, string *thisPointer) +{ + new(thisPointer) string(other); +} + +static void DestructString(string *thisPointer) +{ + thisPointer->~string(); +} + +static string &AddAssignStringToString(const string &str, string &dest) +{ + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration. + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + dest += str; + return dest; +} + +// bool string::isEmpty() +// bool string::empty() // if AS_USE_STLNAMES == 1 +static bool StringIsEmpty(const string &str) +{ + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + return str.empty(); +} + +static string &AssignUInt64ToString(asQWORD i, string &dest) +{ + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; +} + +static string &AddAssignUInt64ToString(asQWORD i, string &dest) +{ + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; +} + +static string AddStringUInt64(const string &str, asQWORD i) +{ + ostringstream stream; + stream << i; + return str + stream.str(); +} + +static string AddInt64String(asINT64 i, const string &str) +{ + ostringstream stream; + stream << i; + return stream.str() + str; +} + +static string &AssignInt64ToString(asINT64 i, string &dest) +{ + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; +} + +static string &AddAssignInt64ToString(asINT64 i, string &dest) +{ + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; +} + +static string AddStringInt64(const string &str, asINT64 i) +{ + ostringstream stream; + stream << i; + return str + stream.str(); +} + +static string AddUInt64String(asQWORD i, const string &str) +{ + ostringstream stream; + stream << i; + return stream.str() + str; +} + +static string &AssignDoubleToString(double f, string &dest) +{ + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; +} + +static string &AddAssignDoubleToString(double f, string &dest) +{ + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; +} + +static string &AssignFloatToString(float f, string &dest) +{ + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; +} + +static string &AddAssignFloatToString(float f, string &dest) +{ + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; +} + +static string &AssignBoolToString(bool b, string &dest) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + dest = stream.str(); + return dest; +} + +static string &AddAssignBoolToString(bool b, string &dest) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + dest += stream.str(); + return dest; +} + +static string AddStringDouble(const string &str, double f) +{ + ostringstream stream; + stream << f; + return str + stream.str(); +} + +static string AddDoubleString(double f, const string &str) +{ + ostringstream stream; + stream << f; + return stream.str() + str; +} + +static string AddStringFloat(const string &str, float f) +{ + ostringstream stream; + stream << f; + return str + stream.str(); +} + +static string AddFloatString(float f, const string &str) +{ + ostringstream stream; + stream << f; + return stream.str() + str; +} + +static string AddStringBool(const string &str, bool b) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + return str + stream.str(); +} + +static string AddBoolString(bool b, const string &str) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + return stream.str() + str; +} + +static char *StringCharAt(unsigned int i, string &str) +{ + if( i >= str.size() ) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); + + // Return a null pointer + return 0; + } + + return &str[i]; +} + +// AngelScript signature: +// int string::opCmp(const string &in) const +static int StringCmp(const string &a, const string &b) +{ + int cmp = 0; + if( a < b ) cmp = -1; + else if( a > b ) cmp = 1; + return cmp; +} + +// This function returns the index of the first position where the substring +// exists in the input string. If the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findFirst(const string &in sub, uint start = 0) const +static int StringFindFirst(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findFirstOf(const string &in sub, uint start = 0) const +static int StringFindFirstOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findLastOf(const string &in sub, uint start = -1) const +static int StringFindLastOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findFirstNotOf(const string &in sub, uint start = 0) const +static int StringFindFirstNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findLastNotOf(const string &in sub, uint start = -1) const +static int StringFindLastNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_not_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where the substring +// exists in the input string. If the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findLast(const string &in sub, int start = -1) const +static int StringFindLast(const string &sub, int start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// AngelScript signature: +// void string::insert(uint pos, const string &in other) +static void StringInsert(unsigned int pos, const string &other, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.insert(pos, other); +} + +// AngelScript signature: +// void string::erase(uint pos, int count = -1) +static void StringErase(unsigned int pos, int count, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.erase(pos, (size_t)(count < 0 ? string::npos : count)); +} + + +// AngelScript signature: +// uint string::length() const +static asUINT StringLength(const string &str) +{ + // We don't register the method directly because the return type changes between 32bit and 64bit platforms + return (asUINT)str.length(); +} + + +// AngelScript signature: +// void string::resize(uint l) +static void StringResize(asUINT l, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.resize(l); +} + +// AngelScript signature: +// string formatInt(int64 val, const string &in options, uint width) +static string formatInt(asINT64 value, const string &options, asUINT width) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + +#ifdef _WIN32 + fmt += "*I64"; +#else +#ifdef _LP64 + fmt += "*l"; +#else + fmt += "*ll"; +#endif +#endif + + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "d"; + + string buf; + buf.resize(width+30); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); +#else + sprintf(&buf[0], fmt.c_str(), width, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// string formatUInt(uint64 val, const string &in options, uint width) +static string formatUInt(asQWORD value, const string &options, asUINT width) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + +#ifdef _WIN32 + fmt += "*I64"; +#else +#ifdef _LP64 + fmt += "*l"; +#else + fmt += "*ll"; +#endif +#endif + + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "u"; + + string buf; + buf.resize(width+30); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); +#else + sprintf(&buf[0], fmt.c_str(), width, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// string formatFloat(double val, const string &in options, uint width, uint precision) +static string formatFloat(double value, const string &options, asUINT width, asUINT precision) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool expSmall = options.find("e") != string::npos; + bool expLarge = options.find("E") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + + fmt += "*.*"; + + if( expSmall ) fmt += "e"; + else if( expLarge ) fmt += "E"; + else fmt += "f"; + + string buf; + buf.resize(width+precision+50); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, precision, value); +#else + sprintf(&buf[0], fmt.c_str(), width, precision, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// int64 parseInt(const string &in val, uint base = 10, uint &out byteCount = 0) +static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) +{ + // Only accept base 10 and 16 + if( base != 10 && base != 16 ) + { + if( byteCount ) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + // Determine the sign + bool sign = false; + if( *end == '-' ) + { + sign = true; + end++; + } + else if( *end == '+' ) + end++; + + asINT64 res = 0; + if( base == 10 ) + { + while( *end >= '0' && *end <= '9' ) + { + res *= 10; + res += *end++ - '0'; + } + } + else if( base == 16 ) + { + while( (*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F') ) + { + res *= 16; + if( *end >= '0' && *end <= '9' ) + res += *end++ - '0'; + else if( *end >= 'a' && *end <= 'f' ) + res += *end++ - 'a' + 10; + else if( *end >= 'A' && *end <= 'F' ) + res += *end++ - 'A' + 10; + } + } + + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); + + if( sign ) + res = -res; + + return res; +} + +// AngelScript signature: +// uint64 parseUInt(const string &in val, uint base = 10, uint &out byteCount = 0) +static asQWORD parseUInt(const string &val, asUINT base, asUINT *byteCount) +{ + // Only accept base 10 and 16 + if (base != 10 && base != 16) + { + if (byteCount) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + asQWORD res = 0; + if (base == 10) + { + while (*end >= '0' && *end <= '9') + { + res *= 10; + res += *end++ - '0'; + } + } + else if (base == 16) + { + while ((*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F')) + { + res *= 16; + if (*end >= '0' && *end <= '9') + res += *end++ - '0'; + else if (*end >= 'a' && *end <= 'f') + res += *end++ - 'a' + 10; + else if (*end >= 'A' && *end <= 'F') + res += *end++ - 'A' + 10; + } + } + + if (byteCount) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; +} + +// AngelScript signature: +// double parseFloat(const string &in val, uint &out byteCount = 0) +double parseFloat(const string &val, asUINT *byteCount) +{ + char *end; + + // WinCE doesn't have setlocale. Some quick testing on my current platform + // still manages to parse the numbers such as "3.14" even if the decimal for the + // locale is ",". +#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) + // Set the locale to C so that we are guaranteed to parse the float value correctly + char *tmp = setlocale(LC_NUMERIC, 0); + string orig = tmp ? tmp : "C"; + setlocale(LC_NUMERIC, "C"); +#endif + + double res = strtod(val.c_str(), &end); + +#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) + // Restore the locale + setlocale(LC_NUMERIC, orig.c_str()); +#endif + + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; +} + +// This function returns a string containing the substring of the input string +// determined by the starting index and count of characters. +// +// AngelScript signature: +// string string::substr(uint start = 0, int count = -1) const +static string StringSubString(asUINT start, int count, const string &str) +{ + // Check for out-of-bounds + string ret; + if( start < str.length() && count != 0 ) + ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); + + return ret; +} + +// String equality comparison. +// Returns true iff lhs is equal to rhs. +// +// For some reason gcc 4.7 has difficulties resolving the +// asFUNCTIONPR(operator==, (const string &, const string &) +// makro, so this wrapper was introduced as work around. +static bool StringEquals(const std::string& lhs, const std::string& rhs) +{ + return lhs == rhs; +} + +void RegisterStdString_Native(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the string type +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); +#endif + + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + + // Need to use a wrapper for operator== otherwise gcc 4.7 fails to compile + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTIONPR(StringEquals, (const string &, const string &), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + + // The string length can be accessed through methods or through virtual property + // TODO: Register as size() for consistency with other types +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + // Don't register these if STL names is used, as they conflict with the method size() + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails +// r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asMETHOD(string, empty), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + // Note that we don't register the operator[] directly, as it doesn't do bounds checking + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Utilities + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); + +#if AS_USE_STLNAMES == 1 + // Same as length + r = engine->RegisterObjectMethod("string", "uint size() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("string", "bool empty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findFirst + r = engine->RegisterObjectMethod("string", "int find(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findLast + r = engine->RegisterObjectMethod("string", "int rfind(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + + // TODO: Implement the following + // findAndReplace - replaces a text found in the string + // replaceRange - replaces a range of bytes in the string + // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" +} + +static void ConstructStringGeneric(asIScriptGeneric * gen) +{ + new (gen->GetObject()) string(); +} + +static void CopyConstructStringGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + new (gen->GetObject()) string(*a); +} + +static void DestructStringGeneric(asIScriptGeneric * gen) +{ + string * ptr = static_cast(gen->GetObject()); + ptr->~string(); +} + +static void AssignStringGeneric(asIScriptGeneric *gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self = *a; + gen->SetReturnAddress(self); +} + +static void AddAssignStringGeneric(asIScriptGeneric *gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self += *a; + gen->SetReturnAddress(self); +} + +static void StringEqualsGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); +} + +static void StringCmpGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + + int cmp = 0; + if( *a < *b ) cmp = -1; + else if( *a > *b ) cmp = 1; + + *(int*)gen->GetAddressOfReturnLocation() = cmp; +} + +static void StringAddGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + string ret_val = *a + *b; + gen->SetReturnObject(&ret_val); +} + +static void StringLengthGeneric(asIScriptGeneric * gen) +{ + string * self = static_cast(gen->GetObject()); + *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); +} + +static void StringIsEmptyGeneric(asIScriptGeneric * gen) +{ + string * self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); +} + +static void StringResizeGeneric(asIScriptGeneric * gen) +{ + string * self = static_cast(gen->GetObject()); + self->resize(*static_cast(gen->GetAddressOfArg(0))); +} + +static void StringInsert_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + string *other = reinterpret_cast(gen->GetArgAddress(1)); + StringInsert(pos, *other, *self); +} + +static void StringErase_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + int count = int(gen->GetArgDWord(1)); + StringErase(pos, count, *self); +} + +static void StringFindFirst_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirst(*find, start, *self); +} + +static void StringFindLast_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); +} + +static void StringFindFirstOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); +} + +static void StringFindLastOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); +} + +static void StringFindFirstNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); +} + +static void StringFindLastNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); +} + +static void formatInt_Generic(asIScriptGeneric * gen) +{ + asINT64 val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); +} + +static void formatUInt_Generic(asIScriptGeneric * gen) +{ + asQWORD val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); +} + +static void formatFloat_Generic(asIScriptGeneric *gen) +{ + double val = gen->GetArgDouble(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + asUINT precision = gen->GetArgDWord(3); + new(gen->GetAddressOfReturnLocation()) string(formatFloat(val, *options, width, precision)); +} + +static void parseInt_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseInt(*str,base,byteCount)); +} + +static void parseUInt_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseUInt(*str, base, byteCount)); +} + +static void parseFloat_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(1)); + gen->SetReturnDouble(parseFloat(*str,byteCount)); +} + +static void StringCharAtGeneric(asIScriptGeneric * gen) +{ + unsigned int index = gen->GetArgDWord(0); + string * self = static_cast(gen->GetObject()); + + if (index >= self->size()) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); + + gen->SetReturnAddress(0); + } + else + { + gen->SetReturnAddress(&(self->operator [](index))); + } +} + +static void AssignInt2StringGeneric(asIScriptGeneric *gen) +{ + asINT64 *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignUInt2StringGeneric(asIScriptGeneric *gen) +{ + asQWORD *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignDouble2StringGeneric(asIScriptGeneric *gen) +{ + double *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignFloat2StringGeneric(asIScriptGeneric *gen) +{ + float *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignBool2StringGeneric(asIScriptGeneric *gen) +{ + bool *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) +{ + double * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen) +{ + float * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) +{ + asINT64 * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) +{ + asQWORD * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) +{ + bool * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddString2DoubleGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + double * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2FloatGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + float * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2IntGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + asINT64 * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2UIntGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + asQWORD * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2BoolGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + bool * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << (*b ? "true" : "false"); + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddDouble2StringGeneric(asIScriptGeneric * gen) +{ + double* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddFloat2StringGeneric(asIScriptGeneric * gen) +{ + float* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddInt2StringGeneric(asIScriptGeneric * gen) +{ + asINT64* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddUInt2StringGeneric(asIScriptGeneric * gen) +{ + asQWORD* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddBool2StringGeneric(asIScriptGeneric * gen) +{ + bool* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false") << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void StringSubString_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + string *str = (string*)gen->GetObject(); + asUINT start = *(int*)gen->GetAddressOfArg(0); + int count = *(int*)gen->GetAddressOfArg(1); + + // Return the substring + new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); +} + +void RegisterStdString_Generic(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the string type + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Register the object methods +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmptyGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); +} + +void RegisterStdString(asIScriptEngine * engine) +{ + if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) + RegisterStdString_Generic(engine); + else + RegisterStdString_Native(engine); +} + +END_AS_NAMESPACE + + + + diff --git a/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.h b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.h new file mode 100644 index 0000000..0960beb --- /dev/null +++ b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring.h @@ -0,0 +1,48 @@ +// +// Script std::string +// +// This function registers the std::string type with AngelScript to be used as the default string type. +// +// The string type is registered as a value type, thus may have performance issues if a lot of +// string operations are performed in the script. However, for relatively few operations, this should +// not cause any problem for most applications. +// + +#ifndef SCRIPTSTDSTRING_H +#define SCRIPTSTDSTRING_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include + +//--------------------------- +// Compilation settings +// + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + +// Some prefer to use property accessors to get/set the length of the string +// This option registers the accessors instead of the method length() +#ifndef AS_USE_ACCESSORS +#define AS_USE_ACCESSORS 0 +#endif + +BEGIN_AS_NAMESPACE + +void RegisterStdString(asIScriptEngine *engine); +void RegisterStdStringUtils(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp new file mode 100644 index 0000000..7b8067f --- /dev/null +++ b/TestRunner/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp @@ -0,0 +1,129 @@ +#include +#include "scriptstdstring.h" +#include "../scriptarray/scriptarray.h" +#include +#include + +using namespace std; + +BEGIN_AS_NAMESPACE + +// This function takes an input string and splits it into parts by looking +// for a specified delimiter. Example: +// +// string str = "A|B||D"; +// array@ array = str.split("|"); +// +// The resulting array has the following elements: +// +// {"A", "B", "", "D"} +// +// AngelScript signature: +// array@ string::split(const string &in delim) const +static CScriptArray *StringSplit(const string &delim, const string &str) +{ + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); + + // Find the existence of the delimiter in the input string + int pos = 0, prev = 0, count = 0; + while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) + { + // Add the part to the array + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev], pos-prev); + + // Find the next part + count++; + prev = pos + (int)delim.length(); + } + + // Add the remaining part + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev]); + + return array; +} + +static void StringSplit_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + string *str = (string*)gen->GetObject(); + string *delim = *(string**)gen->GetAddressOfArg(0); + + // Return the array by handle + *(CScriptArray**)gen->GetAddressOfReturnLocation() = StringSplit(*delim, *str); +} + + + +// This function takes as input an array of string handles as well as a +// delimiter and concatenates the array elements into one delimited string. +// Example: +// +// array array = {"A", "B", "", "D"}; +// string str = join(array, "|"); +// +// The resulting string is: +// +// "A|B||D" +// +// AngelScript signature: +// string join(const array &in array, const string &in delim) +static string StringJoin(const CScriptArray &array, const string &delim) +{ + // Create the new string + string str = ""; + if( array.GetSize() ) + { + int n; + for( n = 0; n < (int)array.GetSize() - 1; n++ ) + { + str += *(string*)array.At(n); + str += delim; + } + + // Add the last part + str += *(string*)array.At(n); + } + + return str; +} + +static void StringJoin_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0); + string *delim = *(string**)gen->GetAddressOfArg(1); + + // Return the string + new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim)); +} + +// This is where the utility functions are registered. +// The string type must have been registered first. +void RegisterStdStringUtils(asIScriptEngine *engine) +{ + [[maybe_unused]] int r; + + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + { + r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); + } + else + { + r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); + } +} + +END_AS_NAMESPACE diff --git a/Testing.py b/Testing.py new file mode 100644 index 0000000..9a5328d --- /dev/null +++ b/Testing.py @@ -0,0 +1,24 @@ +import socket +import sys + +# Create a TCP/IP socket +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Connect the socket to the port where the server is listening +server_address = ('localhost', 8684) +print(sys.stderr, 'connecting to %s port %s' % server_address) +sock.connect(server_address) + +def send(msg): + b = bytes(msg, "utf-8") + sock.send(bytes("Content-Length: " + str(len(b)) + "\r\n\r\n", "ascii")) + sock.send(b) + +send('{"seq": 1, "type": "request", "command": "setBreakpoints", "arguments": {' + '"source": {"path": "TestScript"},' + '"breakpoints": [{ "line": 14} ]' + '} }') + +while True: + msg = sock.recv(128) + print(msg.decode("utf-8")) \ No newline at end of file diff --git a/extern/asio-1.18.2/include/Makefile.am b/extern/asio-1.18.2/include/Makefile.am new file mode 100644 index 0000000..5ff1d26 --- /dev/null +++ b/extern/asio-1.18.2/include/Makefile.am @@ -0,0 +1,566 @@ +# find . -name "*.*pp" | sed -e 's/^\.\///' | sed -e 's/^.*$/ & \\/' | sort +nobase_include_HEADERS = \ + asio/any_io_executor.hpp \ + asio/associated_allocator.hpp \ + asio/associated_executor.hpp \ + asio/async_result.hpp \ + asio/awaitable.hpp \ + asio/basic_datagram_socket.hpp \ + asio/basic_deadline_timer.hpp \ + asio/basic_io_object.hpp \ + asio/basic_raw_socket.hpp \ + asio/basic_seq_packet_socket.hpp \ + asio/basic_serial_port.hpp \ + asio/basic_signal_set.hpp \ + asio/basic_socket_acceptor.hpp \ + asio/basic_socket.hpp \ + asio/basic_socket_iostream.hpp \ + asio/basic_socket_streambuf.hpp \ + asio/basic_streambuf_fwd.hpp \ + asio/basic_streambuf.hpp \ + asio/basic_stream_socket.hpp \ + asio/basic_waitable_timer.hpp \ + asio/bind_executor.hpp \ + asio/buffered_read_stream_fwd.hpp \ + asio/buffered_read_stream.hpp \ + asio/buffered_stream_fwd.hpp \ + asio/buffered_stream.hpp \ + asio/buffered_write_stream_fwd.hpp \ + asio/buffered_write_stream.hpp \ + asio/buffer.hpp \ + asio/buffers_iterator.hpp \ + asio/co_spawn.hpp \ + asio/completion_condition.hpp \ + asio/compose.hpp \ + asio/connect.hpp \ + asio/coroutine.hpp \ + asio/deadline_timer.hpp \ + asio/defer.hpp \ + asio/detached.hpp \ + asio/detail/array_fwd.hpp \ + asio/detail/array.hpp \ + asio/detail/assert.hpp \ + asio/detail/atomic_count.hpp \ + asio/detail/base_from_completion_cond.hpp \ + asio/detail/bind_handler.hpp \ + asio/detail/blocking_executor_op.hpp \ + asio/detail/buffered_stream_storage.hpp \ + asio/detail/buffer_resize_guard.hpp \ + asio/detail/buffer_sequence_adapter.hpp \ + asio/detail/bulk_executor_op.hpp \ + asio/detail/call_stack.hpp \ + asio/detail/chrono.hpp \ + asio/detail/chrono_time_traits.hpp \ + asio/detail/completion_handler.hpp \ + asio/detail/concurrency_hint.hpp \ + asio/detail/conditionally_enabled_event.hpp \ + asio/detail/conditionally_enabled_mutex.hpp \ + asio/detail/config.hpp \ + asio/detail/consuming_buffers.hpp \ + asio/detail/cstddef.hpp \ + asio/detail/cstdint.hpp \ + asio/detail/date_time_fwd.hpp \ + asio/detail/deadline_timer_service.hpp \ + asio/detail/dependent_type.hpp \ + asio/detail/descriptor_ops.hpp \ + asio/detail/descriptor_read_op.hpp \ + asio/detail/descriptor_write_op.hpp \ + asio/detail/dev_poll_reactor.hpp \ + asio/detail/epoll_reactor.hpp \ + asio/detail/eventfd_select_interrupter.hpp \ + asio/detail/event.hpp \ + asio/detail/executor_function.hpp \ + asio/detail/executor_op.hpp \ + asio/detail/fd_set_adapter.hpp \ + asio/detail/fenced_block.hpp \ + asio/detail/functional.hpp \ + asio/detail/future.hpp \ + asio/detail/gcc_arm_fenced_block.hpp \ + asio/detail/gcc_hppa_fenced_block.hpp \ + asio/detail/gcc_sync_fenced_block.hpp \ + asio/detail/gcc_x86_fenced_block.hpp \ + asio/detail/global.hpp \ + asio/detail/handler_alloc_helpers.hpp \ + asio/detail/handler_cont_helpers.hpp \ + asio/detail/handler_invoke_helpers.hpp \ + asio/detail/handler_tracking.hpp \ + asio/detail/handler_type_requirements.hpp \ + asio/detail/handler_work.hpp \ + asio/detail/hash_map.hpp \ + asio/detail/impl/buffer_sequence_adapter.ipp \ + asio/detail/impl/descriptor_ops.ipp \ + asio/detail/impl/dev_poll_reactor.hpp \ + asio/detail/impl/dev_poll_reactor.ipp \ + asio/detail/impl/epoll_reactor.hpp \ + asio/detail/impl/epoll_reactor.ipp \ + asio/detail/impl/eventfd_select_interrupter.ipp \ + asio/detail/impl/handler_tracking.ipp \ + asio/detail/impl/kqueue_reactor.hpp \ + asio/detail/impl/kqueue_reactor.ipp \ + asio/detail/impl/null_event.ipp \ + asio/detail/impl/pipe_select_interrupter.ipp \ + asio/detail/impl/posix_event.ipp \ + asio/detail/impl/posix_mutex.ipp \ + asio/detail/impl/posix_thread.ipp \ + asio/detail/impl/posix_tss_ptr.ipp \ + asio/detail/impl/reactive_descriptor_service.ipp \ + asio/detail/impl/reactive_serial_port_service.ipp \ + asio/detail/impl/reactive_socket_service_base.ipp \ + asio/detail/impl/resolver_service_base.ipp \ + asio/detail/impl/scheduler.ipp \ + asio/detail/impl/select_reactor.hpp \ + asio/detail/impl/select_reactor.ipp \ + asio/detail/impl/service_registry.hpp \ + asio/detail/impl/service_registry.ipp \ + asio/detail/impl/signal_set_service.ipp \ + asio/detail/impl/socket_ops.ipp \ + asio/detail/impl/socket_select_interrupter.ipp \ + asio/detail/impl/strand_executor_service.hpp \ + asio/detail/impl/strand_executor_service.ipp \ + asio/detail/impl/strand_service.hpp \ + asio/detail/impl/strand_service.ipp \ + asio/detail/impl/thread_context.ipp \ + asio/detail/impl/throw_error.ipp \ + asio/detail/impl/timer_queue_ptime.ipp \ + asio/detail/impl/timer_queue_set.ipp \ + asio/detail/impl/win_event.ipp \ + asio/detail/impl/win_iocp_handle_service.ipp \ + asio/detail/impl/win_iocp_io_context.hpp \ + asio/detail/impl/win_iocp_io_context.ipp \ + asio/detail/impl/win_iocp_serial_port_service.ipp \ + asio/detail/impl/win_iocp_socket_service_base.ipp \ + asio/detail/impl/win_mutex.ipp \ + asio/detail/impl/win_object_handle_service.ipp \ + asio/detail/impl/winrt_ssocket_service_base.ipp \ + asio/detail/impl/winrt_timer_scheduler.hpp \ + asio/detail/impl/winrt_timer_scheduler.ipp \ + asio/detail/impl/winsock_init.ipp \ + asio/detail/impl/win_static_mutex.ipp \ + asio/detail/impl/win_thread.ipp \ + asio/detail/impl/win_tss_ptr.ipp \ + asio/detail/io_control.hpp \ + asio/detail/io_object_impl.hpp \ + asio/detail/is_buffer_sequence.hpp \ + asio/detail/is_executor.hpp \ + asio/detail/keyword_tss_ptr.hpp \ + asio/detail/kqueue_reactor.hpp \ + asio/detail/limits.hpp \ + asio/detail/local_free_on_block_exit.hpp \ + asio/detail/macos_fenced_block.hpp \ + asio/detail/memory.hpp \ + asio/detail/mutex.hpp \ + asio/detail/non_const_lvalue.hpp \ + asio/detail/noncopyable.hpp \ + asio/detail/null_event.hpp \ + asio/detail/null_fenced_block.hpp \ + asio/detail/null_global.hpp \ + asio/detail/null_mutex.hpp \ + asio/detail/null_reactor.hpp \ + asio/detail/null_signal_blocker.hpp \ + asio/detail/null_socket_service.hpp \ + asio/detail/null_static_mutex.hpp \ + asio/detail/null_thread.hpp \ + asio/detail/null_tss_ptr.hpp \ + asio/detail/object_pool.hpp \ + asio/detail/old_win_sdk_compat.hpp \ + asio/detail/operation.hpp \ + asio/detail/op_queue.hpp \ + asio/detail/pipe_select_interrupter.hpp \ + asio/detail/pop_options.hpp \ + asio/detail/posix_event.hpp \ + asio/detail/posix_fd_set_adapter.hpp \ + asio/detail/posix_global.hpp \ + asio/detail/posix_mutex.hpp \ + asio/detail/posix_signal_blocker.hpp \ + asio/detail/posix_static_mutex.hpp \ + asio/detail/posix_thread.hpp \ + asio/detail/posix_tss_ptr.hpp \ + asio/detail/push_options.hpp \ + asio/detail/reactive_descriptor_service.hpp \ + asio/detail/reactive_null_buffers_op.hpp \ + asio/detail/reactive_serial_port_service.hpp \ + asio/detail/reactive_socket_accept_op.hpp \ + asio/detail/reactive_socket_connect_op.hpp \ + asio/detail/reactive_socket_recvfrom_op.hpp \ + asio/detail/reactive_socket_recvmsg_op.hpp \ + asio/detail/reactive_socket_recv_op.hpp \ + asio/detail/reactive_socket_send_op.hpp \ + asio/detail/reactive_socket_sendto_op.hpp \ + asio/detail/reactive_socket_service_base.hpp \ + asio/detail/reactive_socket_service.hpp \ + asio/detail/reactive_wait_op.hpp \ + asio/detail/reactor_fwd.hpp \ + asio/detail/reactor.hpp \ + asio/detail/reactor_op.hpp \ + asio/detail/reactor_op_queue.hpp \ + asio/detail/recycling_allocator.hpp \ + asio/detail/regex_fwd.hpp \ + asio/detail/resolve_endpoint_op.hpp \ + asio/detail/resolve_op.hpp \ + asio/detail/resolve_query_op.hpp \ + asio/detail/resolver_service_base.hpp \ + asio/detail/resolver_service.hpp \ + asio/detail/scheduler.hpp \ + asio/detail/scheduler_operation.hpp \ + asio/detail/scheduler_thread_info.hpp \ + asio/detail/scoped_lock.hpp \ + asio/detail/scoped_ptr.hpp \ + asio/detail/select_interrupter.hpp \ + asio/detail/select_reactor.hpp \ + asio/detail/service_registry.hpp \ + asio/detail/signal_blocker.hpp \ + asio/detail/signal_handler.hpp \ + asio/detail/signal_init.hpp \ + asio/detail/signal_op.hpp \ + asio/detail/signal_set_service.hpp \ + asio/detail/socket_holder.hpp \ + asio/detail/socket_ops.hpp \ + asio/detail/socket_option.hpp \ + asio/detail/socket_select_interrupter.hpp \ + asio/detail/socket_types.hpp \ + asio/detail/solaris_fenced_block.hpp \ + asio/detail/source_location.hpp \ + asio/detail/static_mutex.hpp \ + asio/detail/std_event.hpp \ + asio/detail/std_fenced_block.hpp \ + asio/detail/std_global.hpp \ + asio/detail/std_mutex.hpp \ + asio/detail/std_static_mutex.hpp \ + asio/detail/std_thread.hpp \ + asio/detail/strand_executor_service.hpp \ + asio/detail/strand_service.hpp \ + asio/detail/string_view.hpp \ + asio/detail/thread_context.hpp \ + asio/detail/thread_group.hpp \ + asio/detail/thread.hpp \ + asio/detail/thread_info_base.hpp \ + asio/detail/throw_error.hpp \ + asio/detail/throw_exception.hpp \ + asio/detail/timer_queue_base.hpp \ + asio/detail/timer_queue.hpp \ + asio/detail/timer_queue_ptime.hpp \ + asio/detail/timer_queue_set.hpp \ + asio/detail/timer_scheduler_fwd.hpp \ + asio/detail/timer_scheduler.hpp \ + asio/detail/tss_ptr.hpp \ + asio/detail/type_traits.hpp \ + asio/detail/variadic_templates.hpp \ + asio/detail/wait_handler.hpp \ + asio/detail/wait_op.hpp \ + asio/detail/winapp_thread.hpp \ + asio/detail/wince_thread.hpp \ + asio/detail/win_event.hpp \ + asio/detail/win_fd_set_adapter.hpp \ + asio/detail/win_fenced_block.hpp \ + asio/detail/win_global.hpp \ + asio/detail/win_iocp_handle_read_op.hpp \ + asio/detail/win_iocp_handle_service.hpp \ + asio/detail/win_iocp_handle_write_op.hpp \ + asio/detail/win_iocp_io_context.hpp \ + asio/detail/win_iocp_null_buffers_op.hpp \ + asio/detail/win_iocp_operation.hpp \ + asio/detail/win_iocp_overlapped_op.hpp \ + asio/detail/win_iocp_overlapped_ptr.hpp \ + asio/detail/win_iocp_serial_port_service.hpp \ + asio/detail/win_iocp_socket_accept_op.hpp \ + asio/detail/win_iocp_socket_connect_op.hpp \ + asio/detail/win_iocp_socket_recvfrom_op.hpp \ + asio/detail/win_iocp_socket_recvmsg_op.hpp \ + asio/detail/win_iocp_socket_recv_op.hpp \ + asio/detail/win_iocp_socket_send_op.hpp \ + asio/detail/win_iocp_socket_service_base.hpp \ + asio/detail/win_iocp_socket_service.hpp \ + asio/detail/win_iocp_thread_info.hpp \ + asio/detail/win_iocp_wait_op.hpp \ + asio/detail/win_mutex.hpp \ + asio/detail/win_object_handle_service.hpp \ + asio/detail/winrt_async_manager.hpp \ + asio/detail/winrt_async_op.hpp \ + asio/detail/winrt_resolve_op.hpp \ + asio/detail/winrt_resolver_service.hpp \ + asio/detail/winrt_socket_connect_op.hpp \ + asio/detail/winrt_socket_recv_op.hpp \ + asio/detail/winrt_socket_send_op.hpp \ + asio/detail/winrt_ssocket_service_base.hpp \ + asio/detail/winrt_ssocket_service.hpp \ + asio/detail/winrt_timer_scheduler.hpp \ + asio/detail/winrt_utils.hpp \ + asio/detail/winsock_init.hpp \ + asio/detail/win_static_mutex.hpp \ + asio/detail/win_thread.hpp \ + asio/detail/win_tss_ptr.hpp \ + asio/detail/work_dispatcher.hpp \ + asio/detail/wrapped_handler.hpp \ + asio/dispatch.hpp \ + asio/error_code.hpp \ + asio/error.hpp \ + asio/execution.hpp \ + asio/execution_context.hpp \ + asio/execution/allocator.hpp \ + asio/execution/any_executor.hpp \ + asio/execution/bad_executor.hpp \ + asio/execution/blocking.hpp \ + asio/execution/blocking_adaptation.hpp \ + asio/execution/bulk_execute.hpp \ + asio/execution/bulk_guarantee.hpp \ + asio/execution/connect.hpp \ + asio/execution/context.hpp \ + asio/execution/context_as.hpp \ + asio/execution/detail/as_invocable.hpp \ + asio/execution/detail/as_operation.hpp \ + asio/execution/detail/as_receiver.hpp \ + asio/execution/detail/bulk_sender.hpp \ + asio/execution/detail/void_receiver.hpp \ + asio/execution/detail/submit_receiver.hpp \ + asio/execution/execute.hpp \ + asio/execution/executor.hpp \ + asio/execution/impl/bad_executor.ipp \ + asio/execution/impl/receiver_invocation_error.ipp \ + asio/execution/invocable_archetype.hpp \ + asio/execution/mapping.hpp \ + asio/execution/occupancy.hpp \ + asio/execution/operation_state.hpp \ + asio/execution/outstanding_work.hpp \ + asio/execution/prefer_only.hpp \ + asio/execution/receiver.hpp \ + asio/execution/receiver_invocation_error.hpp \ + asio/execution/relationship.hpp \ + asio/execution/schedule.hpp \ + asio/execution/scheduler.hpp \ + asio/execution/sender.hpp \ + asio/execution/set_done.hpp \ + asio/execution/set_error.hpp \ + asio/execution/set_value.hpp \ + asio/execution/start.hpp \ + asio/execution/submit.hpp \ + asio/executor.hpp \ + asio/executor_work_guard.hpp \ + asio/experimental/as_single.hpp \ + asio/experimental/impl/as_single.hpp \ + asio/generic/basic_endpoint.hpp \ + asio/generic/datagram_protocol.hpp \ + asio/generic/detail/endpoint.hpp \ + asio/generic/detail/impl/endpoint.ipp \ + asio/generic/raw_protocol.hpp \ + asio/generic/seq_packet_protocol.hpp \ + asio/generic/stream_protocol.hpp \ + asio/handler_alloc_hook.hpp \ + asio/handler_continuation_hook.hpp \ + asio/handler_invoke_hook.hpp \ + asio/high_resolution_timer.hpp \ + asio.hpp \ + asio/impl/awaitable.hpp \ + asio/impl/buffered_read_stream.hpp \ + asio/impl/buffered_write_stream.hpp \ + asio/impl/co_spawn.hpp \ + asio/impl/compose.hpp \ + asio/impl/connect.hpp \ + asio/impl/defer.hpp \ + asio/impl/detached.hpp \ + asio/impl/dispatch.hpp \ + asio/impl/error_code.ipp \ + asio/impl/error.ipp \ + asio/impl/execution_context.hpp \ + asio/impl/execution_context.ipp \ + asio/impl/executor.hpp \ + asio/impl/executor.ipp \ + asio/impl/handler_alloc_hook.ipp \ + asio/impl/io_context.hpp \ + asio/impl/io_context.ipp \ + asio/impl/multiple_exceptions.ipp \ + asio/impl/post.hpp \ + asio/impl/read_at.hpp \ + asio/impl/read.hpp \ + asio/impl/read_until.hpp \ + asio/impl/redirect_error.hpp \ + asio/impl/serial_port_base.hpp \ + asio/impl/serial_port_base.ipp \ + asio/impl/spawn.hpp \ + asio/impl/src.hpp \ + asio/impl/system_context.hpp \ + asio/impl/system_context.ipp \ + asio/impl/system_executor.hpp \ + asio/impl/thread_pool.hpp \ + asio/impl/thread_pool.ipp \ + asio/impl/use_awaitable.hpp \ + asio/impl/use_future.hpp \ + asio/impl/write_at.hpp \ + asio/impl/write.hpp \ + asio/io_context.hpp \ + asio/io_context_strand.hpp \ + asio/io_service.hpp \ + asio/io_service_strand.hpp \ + asio/ip/address.hpp \ + asio/ip/address_v4.hpp \ + asio/ip/address_v4_iterator.hpp \ + asio/ip/address_v4_range.hpp \ + asio/ip/address_v6.hpp \ + asio/ip/address_v6_iterator.hpp \ + asio/ip/address_v6_range.hpp \ + asio/ip/bad_address_cast.hpp \ + asio/ip/basic_endpoint.hpp \ + asio/ip/basic_resolver_entry.hpp \ + asio/ip/basic_resolver.hpp \ + asio/ip/basic_resolver_iterator.hpp \ + asio/ip/basic_resolver_query.hpp \ + asio/ip/basic_resolver_results.hpp \ + asio/ip/detail/endpoint.hpp \ + asio/ip/detail/impl/endpoint.ipp \ + asio/ip/detail/socket_option.hpp \ + asio/ip/host_name.hpp \ + asio/ip/icmp.hpp \ + asio/ip/impl/address.hpp \ + asio/ip/impl/address.ipp \ + asio/ip/impl/address_v4.hpp \ + asio/ip/impl/address_v4.ipp \ + asio/ip/impl/address_v6.hpp \ + asio/ip/impl/address_v6.ipp \ + asio/ip/impl/basic_endpoint.hpp \ + asio/ip/impl/host_name.ipp \ + asio/ip/impl/network_v4.hpp \ + asio/ip/impl/network_v4.ipp \ + asio/ip/impl/network_v6.hpp \ + asio/ip/impl/network_v6.ipp \ + asio/ip/multicast.hpp \ + asio/ip/network_v4.hpp \ + asio/ip/network_v6.hpp \ + asio/ip/resolver_base.hpp \ + asio/ip/resolver_query_base.hpp \ + asio/ip/tcp.hpp \ + asio/ip/udp.hpp \ + asio/ip/unicast.hpp \ + asio/ip/v6_only.hpp \ + asio/is_applicable_property.hpp \ + asio/is_executor.hpp \ + asio/is_read_buffered.hpp \ + asio/is_write_buffered.hpp \ + asio/local/basic_endpoint.hpp \ + asio/local/connect_pair.hpp \ + asio/local/datagram_protocol.hpp \ + asio/local/detail/endpoint.hpp \ + asio/local/detail/impl/endpoint.ipp \ + asio/local/stream_protocol.hpp \ + asio/multiple_exceptions.hpp \ + asio/packaged_task.hpp \ + asio/placeholders.hpp \ + asio/posix/basic_descriptor.hpp \ + asio/posix/basic_stream_descriptor.hpp \ + asio/posix/descriptor_base.hpp \ + asio/posix/descriptor.hpp \ + asio/posix/stream_descriptor.hpp \ + asio/post.hpp \ + asio/prefer.hpp \ + asio/query.hpp \ + asio/read_at.hpp \ + asio/read.hpp \ + asio/read_until.hpp \ + asio/redirect_error.hpp \ + asio/require.hpp \ + asio/require_concept.hpp \ + asio/serial_port_base.hpp \ + asio/serial_port.hpp \ + asio/signal_set.hpp \ + asio/socket_base.hpp \ + asio/spawn.hpp \ + asio/ssl/context_base.hpp \ + asio/ssl/context.hpp \ + asio/ssl/detail/buffered_handshake_op.hpp \ + asio/ssl/detail/engine.hpp \ + asio/ssl/detail/handshake_op.hpp \ + asio/ssl/detail/impl/engine.ipp \ + asio/ssl/detail/impl/openssl_init.ipp \ + asio/ssl/detail/io.hpp \ + asio/ssl/detail/openssl_init.hpp \ + asio/ssl/detail/openssl_types.hpp \ + asio/ssl/detail/password_callback.hpp \ + asio/ssl/detail/read_op.hpp \ + asio/ssl/detail/shutdown_op.hpp \ + asio/ssl/detail/stream_core.hpp \ + asio/ssl/detail/verify_callback.hpp \ + asio/ssl/detail/write_op.hpp \ + asio/ssl/error.hpp \ + asio/ssl.hpp \ + asio/ssl/host_name_verification.hpp \ + asio/ssl/impl/context.hpp \ + asio/ssl/impl/context.ipp \ + asio/ssl/impl/error.ipp \ + asio/ssl/impl/host_name_verification.ipp \ + asio/ssl/impl/rfc2818_verification.ipp \ + asio/ssl/impl/src.hpp \ + asio/ssl/rfc2818_verification.hpp \ + asio/ssl/stream_base.hpp \ + asio/ssl/stream.hpp \ + asio/ssl/verify_context.hpp \ + asio/ssl/verify_mode.hpp \ + asio/static_thread_pool.hpp \ + asio/steady_timer.hpp \ + asio/strand.hpp \ + asio/streambuf.hpp \ + asio/system_context.hpp \ + asio/system_error.hpp \ + asio/system_executor.hpp \ + asio/system_timer.hpp \ + asio/this_coro.hpp \ + asio/thread.hpp \ + asio/thread_pool.hpp \ + asio/time_traits.hpp \ + asio/traits/bulk_execute_free.hpp \ + asio/traits/bulk_execute_member.hpp \ + asio/traits/connect_free.hpp \ + asio/traits/connect_member.hpp \ + asio/traits/equality_comparable.hpp \ + asio/traits/execute_free.hpp \ + asio/traits/execute_member.hpp \ + asio/traits/prefer_free.hpp \ + asio/traits/prefer_member.hpp \ + asio/traits/query_free.hpp \ + asio/traits/query_member.hpp \ + asio/traits/query_static_constexpr_member.hpp \ + asio/traits/require_concept_free.hpp \ + asio/traits/require_concept_member.hpp \ + asio/traits/require_free.hpp \ + asio/traits/require_member.hpp \ + asio/traits/schedule_free.hpp \ + asio/traits/schedule_member.hpp \ + asio/traits/set_done_free.hpp \ + asio/traits/set_done_member.hpp \ + asio/traits/set_error_free.hpp \ + asio/traits/set_error_member.hpp \ + asio/traits/set_value_free.hpp \ + asio/traits/set_value_member.hpp \ + asio/traits/start_free.hpp \ + asio/traits/start_member.hpp \ + asio/traits/static_query.hpp \ + asio/traits/static_require.hpp \ + asio/traits/static_require_concept.hpp \ + asio/traits/submit_free.hpp \ + asio/traits/submit_member.hpp \ + asio/ts/buffer.hpp \ + asio/ts/executor.hpp \ + asio/ts/internet.hpp \ + asio/ts/io_context.hpp \ + asio/ts/netfwd.hpp \ + asio/ts/net.hpp \ + asio/ts/socket.hpp \ + asio/ts/timer.hpp \ + asio/unyield.hpp \ + asio/use_awaitable.hpp \ + asio/use_future.hpp \ + asio/uses_executor.hpp \ + asio/version.hpp \ + asio/wait_traits.hpp \ + asio/windows/basic_object_handle.hpp \ + asio/windows/basic_overlapped_handle.hpp \ + asio/windows/basic_random_access_handle.hpp \ + asio/windows/basic_stream_handle.hpp \ + asio/windows/object_handle.hpp \ + asio/windows/overlapped_handle.hpp \ + asio/windows/overlapped_ptr.hpp \ + asio/windows/random_access_handle.hpp \ + asio/windows/stream_handle.hpp \ + asio/write_at.hpp \ + asio/write.hpp \ + asio/yield.hpp + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in diff --git a/extern/asio-1.18.2/include/Makefile.in b/extern/asio-1.18.2/include/Makefile.in new file mode 100644 index 0000000..fc25627 --- /dev/null +++ b/extern/asio-1.18.2/include/Makefile.in @@ -0,0 +1,1105 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(nobase_include_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(includedir)" +HEADERS = $(nobase_include_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# find . -name "*.*pp" | sed -e 's/^\.\///' | sed -e 's/^.*$/ & \\/' | sort +nobase_include_HEADERS = \ + asio/any_io_executor.hpp \ + asio/associated_allocator.hpp \ + asio/associated_executor.hpp \ + asio/async_result.hpp \ + asio/awaitable.hpp \ + asio/basic_datagram_socket.hpp \ + asio/basic_deadline_timer.hpp \ + asio/basic_io_object.hpp \ + asio/basic_raw_socket.hpp \ + asio/basic_seq_packet_socket.hpp \ + asio/basic_serial_port.hpp \ + asio/basic_signal_set.hpp \ + asio/basic_socket_acceptor.hpp \ + asio/basic_socket.hpp \ + asio/basic_socket_iostream.hpp \ + asio/basic_socket_streambuf.hpp \ + asio/basic_streambuf_fwd.hpp \ + asio/basic_streambuf.hpp \ + asio/basic_stream_socket.hpp \ + asio/basic_waitable_timer.hpp \ + asio/bind_executor.hpp \ + asio/buffered_read_stream_fwd.hpp \ + asio/buffered_read_stream.hpp \ + asio/buffered_stream_fwd.hpp \ + asio/buffered_stream.hpp \ + asio/buffered_write_stream_fwd.hpp \ + asio/buffered_write_stream.hpp \ + asio/buffer.hpp \ + asio/buffers_iterator.hpp \ + asio/co_spawn.hpp \ + asio/completion_condition.hpp \ + asio/compose.hpp \ + asio/connect.hpp \ + asio/coroutine.hpp \ + asio/deadline_timer.hpp \ + asio/defer.hpp \ + asio/detached.hpp \ + asio/detail/array_fwd.hpp \ + asio/detail/array.hpp \ + asio/detail/assert.hpp \ + asio/detail/atomic_count.hpp \ + asio/detail/base_from_completion_cond.hpp \ + asio/detail/bind_handler.hpp \ + asio/detail/blocking_executor_op.hpp \ + asio/detail/buffered_stream_storage.hpp \ + asio/detail/buffer_resize_guard.hpp \ + asio/detail/buffer_sequence_adapter.hpp \ + asio/detail/bulk_executor_op.hpp \ + asio/detail/call_stack.hpp \ + asio/detail/chrono.hpp \ + asio/detail/chrono_time_traits.hpp \ + asio/detail/completion_handler.hpp \ + asio/detail/concurrency_hint.hpp \ + asio/detail/conditionally_enabled_event.hpp \ + asio/detail/conditionally_enabled_mutex.hpp \ + asio/detail/config.hpp \ + asio/detail/consuming_buffers.hpp \ + asio/detail/cstddef.hpp \ + asio/detail/cstdint.hpp \ + asio/detail/date_time_fwd.hpp \ + asio/detail/deadline_timer_service.hpp \ + asio/detail/dependent_type.hpp \ + asio/detail/descriptor_ops.hpp \ + asio/detail/descriptor_read_op.hpp \ + asio/detail/descriptor_write_op.hpp \ + asio/detail/dev_poll_reactor.hpp \ + asio/detail/epoll_reactor.hpp \ + asio/detail/eventfd_select_interrupter.hpp \ + asio/detail/event.hpp \ + asio/detail/executor_function.hpp \ + asio/detail/executor_op.hpp \ + asio/detail/fd_set_adapter.hpp \ + asio/detail/fenced_block.hpp \ + asio/detail/functional.hpp \ + asio/detail/future.hpp \ + asio/detail/gcc_arm_fenced_block.hpp \ + asio/detail/gcc_hppa_fenced_block.hpp \ + asio/detail/gcc_sync_fenced_block.hpp \ + asio/detail/gcc_x86_fenced_block.hpp \ + asio/detail/global.hpp \ + asio/detail/handler_alloc_helpers.hpp \ + asio/detail/handler_cont_helpers.hpp \ + asio/detail/handler_invoke_helpers.hpp \ + asio/detail/handler_tracking.hpp \ + asio/detail/handler_type_requirements.hpp \ + asio/detail/handler_work.hpp \ + asio/detail/hash_map.hpp \ + asio/detail/impl/buffer_sequence_adapter.ipp \ + asio/detail/impl/descriptor_ops.ipp \ + asio/detail/impl/dev_poll_reactor.hpp \ + asio/detail/impl/dev_poll_reactor.ipp \ + asio/detail/impl/epoll_reactor.hpp \ + asio/detail/impl/epoll_reactor.ipp \ + asio/detail/impl/eventfd_select_interrupter.ipp \ + asio/detail/impl/handler_tracking.ipp \ + asio/detail/impl/kqueue_reactor.hpp \ + asio/detail/impl/kqueue_reactor.ipp \ + asio/detail/impl/null_event.ipp \ + asio/detail/impl/pipe_select_interrupter.ipp \ + asio/detail/impl/posix_event.ipp \ + asio/detail/impl/posix_mutex.ipp \ + asio/detail/impl/posix_thread.ipp \ + asio/detail/impl/posix_tss_ptr.ipp \ + asio/detail/impl/reactive_descriptor_service.ipp \ + asio/detail/impl/reactive_serial_port_service.ipp \ + asio/detail/impl/reactive_socket_service_base.ipp \ + asio/detail/impl/resolver_service_base.ipp \ + asio/detail/impl/scheduler.ipp \ + asio/detail/impl/select_reactor.hpp \ + asio/detail/impl/select_reactor.ipp \ + asio/detail/impl/service_registry.hpp \ + asio/detail/impl/service_registry.ipp \ + asio/detail/impl/signal_set_service.ipp \ + asio/detail/impl/socket_ops.ipp \ + asio/detail/impl/socket_select_interrupter.ipp \ + asio/detail/impl/strand_executor_service.hpp \ + asio/detail/impl/strand_executor_service.ipp \ + asio/detail/impl/strand_service.hpp \ + asio/detail/impl/strand_service.ipp \ + asio/detail/impl/thread_context.ipp \ + asio/detail/impl/throw_error.ipp \ + asio/detail/impl/timer_queue_ptime.ipp \ + asio/detail/impl/timer_queue_set.ipp \ + asio/detail/impl/win_event.ipp \ + asio/detail/impl/win_iocp_handle_service.ipp \ + asio/detail/impl/win_iocp_io_context.hpp \ + asio/detail/impl/win_iocp_io_context.ipp \ + asio/detail/impl/win_iocp_serial_port_service.ipp \ + asio/detail/impl/win_iocp_socket_service_base.ipp \ + asio/detail/impl/win_mutex.ipp \ + asio/detail/impl/win_object_handle_service.ipp \ + asio/detail/impl/winrt_ssocket_service_base.ipp \ + asio/detail/impl/winrt_timer_scheduler.hpp \ + asio/detail/impl/winrt_timer_scheduler.ipp \ + asio/detail/impl/winsock_init.ipp \ + asio/detail/impl/win_static_mutex.ipp \ + asio/detail/impl/win_thread.ipp \ + asio/detail/impl/win_tss_ptr.ipp \ + asio/detail/io_control.hpp \ + asio/detail/io_object_impl.hpp \ + asio/detail/is_buffer_sequence.hpp \ + asio/detail/is_executor.hpp \ + asio/detail/keyword_tss_ptr.hpp \ + asio/detail/kqueue_reactor.hpp \ + asio/detail/limits.hpp \ + asio/detail/local_free_on_block_exit.hpp \ + asio/detail/macos_fenced_block.hpp \ + asio/detail/memory.hpp \ + asio/detail/mutex.hpp \ + asio/detail/non_const_lvalue.hpp \ + asio/detail/noncopyable.hpp \ + asio/detail/null_event.hpp \ + asio/detail/null_fenced_block.hpp \ + asio/detail/null_global.hpp \ + asio/detail/null_mutex.hpp \ + asio/detail/null_reactor.hpp \ + asio/detail/null_signal_blocker.hpp \ + asio/detail/null_socket_service.hpp \ + asio/detail/null_static_mutex.hpp \ + asio/detail/null_thread.hpp \ + asio/detail/null_tss_ptr.hpp \ + asio/detail/object_pool.hpp \ + asio/detail/old_win_sdk_compat.hpp \ + asio/detail/operation.hpp \ + asio/detail/op_queue.hpp \ + asio/detail/pipe_select_interrupter.hpp \ + asio/detail/pop_options.hpp \ + asio/detail/posix_event.hpp \ + asio/detail/posix_fd_set_adapter.hpp \ + asio/detail/posix_global.hpp \ + asio/detail/posix_mutex.hpp \ + asio/detail/posix_signal_blocker.hpp \ + asio/detail/posix_static_mutex.hpp \ + asio/detail/posix_thread.hpp \ + asio/detail/posix_tss_ptr.hpp \ + asio/detail/push_options.hpp \ + asio/detail/reactive_descriptor_service.hpp \ + asio/detail/reactive_null_buffers_op.hpp \ + asio/detail/reactive_serial_port_service.hpp \ + asio/detail/reactive_socket_accept_op.hpp \ + asio/detail/reactive_socket_connect_op.hpp \ + asio/detail/reactive_socket_recvfrom_op.hpp \ + asio/detail/reactive_socket_recvmsg_op.hpp \ + asio/detail/reactive_socket_recv_op.hpp \ + asio/detail/reactive_socket_send_op.hpp \ + asio/detail/reactive_socket_sendto_op.hpp \ + asio/detail/reactive_socket_service_base.hpp \ + asio/detail/reactive_socket_service.hpp \ + asio/detail/reactive_wait_op.hpp \ + asio/detail/reactor_fwd.hpp \ + asio/detail/reactor.hpp \ + asio/detail/reactor_op.hpp \ + asio/detail/reactor_op_queue.hpp \ + asio/detail/recycling_allocator.hpp \ + asio/detail/regex_fwd.hpp \ + asio/detail/resolve_endpoint_op.hpp \ + asio/detail/resolve_op.hpp \ + asio/detail/resolve_query_op.hpp \ + asio/detail/resolver_service_base.hpp \ + asio/detail/resolver_service.hpp \ + asio/detail/scheduler.hpp \ + asio/detail/scheduler_operation.hpp \ + asio/detail/scheduler_thread_info.hpp \ + asio/detail/scoped_lock.hpp \ + asio/detail/scoped_ptr.hpp \ + asio/detail/select_interrupter.hpp \ + asio/detail/select_reactor.hpp \ + asio/detail/service_registry.hpp \ + asio/detail/signal_blocker.hpp \ + asio/detail/signal_handler.hpp \ + asio/detail/signal_init.hpp \ + asio/detail/signal_op.hpp \ + asio/detail/signal_set_service.hpp \ + asio/detail/socket_holder.hpp \ + asio/detail/socket_ops.hpp \ + asio/detail/socket_option.hpp \ + asio/detail/socket_select_interrupter.hpp \ + asio/detail/socket_types.hpp \ + asio/detail/solaris_fenced_block.hpp \ + asio/detail/source_location.hpp \ + asio/detail/static_mutex.hpp \ + asio/detail/std_event.hpp \ + asio/detail/std_fenced_block.hpp \ + asio/detail/std_global.hpp \ + asio/detail/std_mutex.hpp \ + asio/detail/std_static_mutex.hpp \ + asio/detail/std_thread.hpp \ + asio/detail/strand_executor_service.hpp \ + asio/detail/strand_service.hpp \ + asio/detail/string_view.hpp \ + asio/detail/thread_context.hpp \ + asio/detail/thread_group.hpp \ + asio/detail/thread.hpp \ + asio/detail/thread_info_base.hpp \ + asio/detail/throw_error.hpp \ + asio/detail/throw_exception.hpp \ + asio/detail/timer_queue_base.hpp \ + asio/detail/timer_queue.hpp \ + asio/detail/timer_queue_ptime.hpp \ + asio/detail/timer_queue_set.hpp \ + asio/detail/timer_scheduler_fwd.hpp \ + asio/detail/timer_scheduler.hpp \ + asio/detail/tss_ptr.hpp \ + asio/detail/type_traits.hpp \ + asio/detail/variadic_templates.hpp \ + asio/detail/wait_handler.hpp \ + asio/detail/wait_op.hpp \ + asio/detail/winapp_thread.hpp \ + asio/detail/wince_thread.hpp \ + asio/detail/win_event.hpp \ + asio/detail/win_fd_set_adapter.hpp \ + asio/detail/win_fenced_block.hpp \ + asio/detail/win_global.hpp \ + asio/detail/win_iocp_handle_read_op.hpp \ + asio/detail/win_iocp_handle_service.hpp \ + asio/detail/win_iocp_handle_write_op.hpp \ + asio/detail/win_iocp_io_context.hpp \ + asio/detail/win_iocp_null_buffers_op.hpp \ + asio/detail/win_iocp_operation.hpp \ + asio/detail/win_iocp_overlapped_op.hpp \ + asio/detail/win_iocp_overlapped_ptr.hpp \ + asio/detail/win_iocp_serial_port_service.hpp \ + asio/detail/win_iocp_socket_accept_op.hpp \ + asio/detail/win_iocp_socket_connect_op.hpp \ + asio/detail/win_iocp_socket_recvfrom_op.hpp \ + asio/detail/win_iocp_socket_recvmsg_op.hpp \ + asio/detail/win_iocp_socket_recv_op.hpp \ + asio/detail/win_iocp_socket_send_op.hpp \ + asio/detail/win_iocp_socket_service_base.hpp \ + asio/detail/win_iocp_socket_service.hpp \ + asio/detail/win_iocp_thread_info.hpp \ + asio/detail/win_iocp_wait_op.hpp \ + asio/detail/win_mutex.hpp \ + asio/detail/win_object_handle_service.hpp \ + asio/detail/winrt_async_manager.hpp \ + asio/detail/winrt_async_op.hpp \ + asio/detail/winrt_resolve_op.hpp \ + asio/detail/winrt_resolver_service.hpp \ + asio/detail/winrt_socket_connect_op.hpp \ + asio/detail/winrt_socket_recv_op.hpp \ + asio/detail/winrt_socket_send_op.hpp \ + asio/detail/winrt_ssocket_service_base.hpp \ + asio/detail/winrt_ssocket_service.hpp \ + asio/detail/winrt_timer_scheduler.hpp \ + asio/detail/winrt_utils.hpp \ + asio/detail/winsock_init.hpp \ + asio/detail/win_static_mutex.hpp \ + asio/detail/win_thread.hpp \ + asio/detail/win_tss_ptr.hpp \ + asio/detail/work_dispatcher.hpp \ + asio/detail/wrapped_handler.hpp \ + asio/dispatch.hpp \ + asio/error_code.hpp \ + asio/error.hpp \ + asio/execution.hpp \ + asio/execution_context.hpp \ + asio/execution/allocator.hpp \ + asio/execution/any_executor.hpp \ + asio/execution/bad_executor.hpp \ + asio/execution/blocking.hpp \ + asio/execution/blocking_adaptation.hpp \ + asio/execution/bulk_execute.hpp \ + asio/execution/bulk_guarantee.hpp \ + asio/execution/connect.hpp \ + asio/execution/context.hpp \ + asio/execution/context_as.hpp \ + asio/execution/detail/as_invocable.hpp \ + asio/execution/detail/as_operation.hpp \ + asio/execution/detail/as_receiver.hpp \ + asio/execution/detail/bulk_sender.hpp \ + asio/execution/detail/void_receiver.hpp \ + asio/execution/detail/submit_receiver.hpp \ + asio/execution/execute.hpp \ + asio/execution/executor.hpp \ + asio/execution/impl/bad_executor.ipp \ + asio/execution/impl/receiver_invocation_error.ipp \ + asio/execution/invocable_archetype.hpp \ + asio/execution/mapping.hpp \ + asio/execution/occupancy.hpp \ + asio/execution/operation_state.hpp \ + asio/execution/outstanding_work.hpp \ + asio/execution/prefer_only.hpp \ + asio/execution/receiver.hpp \ + asio/execution/receiver_invocation_error.hpp \ + asio/execution/relationship.hpp \ + asio/execution/schedule.hpp \ + asio/execution/scheduler.hpp \ + asio/execution/sender.hpp \ + asio/execution/set_done.hpp \ + asio/execution/set_error.hpp \ + asio/execution/set_value.hpp \ + asio/execution/start.hpp \ + asio/execution/submit.hpp \ + asio/executor.hpp \ + asio/executor_work_guard.hpp \ + asio/experimental/as_single.hpp \ + asio/experimental/impl/as_single.hpp \ + asio/generic/basic_endpoint.hpp \ + asio/generic/datagram_protocol.hpp \ + asio/generic/detail/endpoint.hpp \ + asio/generic/detail/impl/endpoint.ipp \ + asio/generic/raw_protocol.hpp \ + asio/generic/seq_packet_protocol.hpp \ + asio/generic/stream_protocol.hpp \ + asio/handler_alloc_hook.hpp \ + asio/handler_continuation_hook.hpp \ + asio/handler_invoke_hook.hpp \ + asio/high_resolution_timer.hpp \ + asio.hpp \ + asio/impl/awaitable.hpp \ + asio/impl/buffered_read_stream.hpp \ + asio/impl/buffered_write_stream.hpp \ + asio/impl/co_spawn.hpp \ + asio/impl/compose.hpp \ + asio/impl/connect.hpp \ + asio/impl/defer.hpp \ + asio/impl/detached.hpp \ + asio/impl/dispatch.hpp \ + asio/impl/error_code.ipp \ + asio/impl/error.ipp \ + asio/impl/execution_context.hpp \ + asio/impl/execution_context.ipp \ + asio/impl/executor.hpp \ + asio/impl/executor.ipp \ + asio/impl/handler_alloc_hook.ipp \ + asio/impl/io_context.hpp \ + asio/impl/io_context.ipp \ + asio/impl/multiple_exceptions.ipp \ + asio/impl/post.hpp \ + asio/impl/read_at.hpp \ + asio/impl/read.hpp \ + asio/impl/read_until.hpp \ + asio/impl/redirect_error.hpp \ + asio/impl/serial_port_base.hpp \ + asio/impl/serial_port_base.ipp \ + asio/impl/spawn.hpp \ + asio/impl/src.hpp \ + asio/impl/system_context.hpp \ + asio/impl/system_context.ipp \ + asio/impl/system_executor.hpp \ + asio/impl/thread_pool.hpp \ + asio/impl/thread_pool.ipp \ + asio/impl/use_awaitable.hpp \ + asio/impl/use_future.hpp \ + asio/impl/write_at.hpp \ + asio/impl/write.hpp \ + asio/io_context.hpp \ + asio/io_context_strand.hpp \ + asio/io_service.hpp \ + asio/io_service_strand.hpp \ + asio/ip/address.hpp \ + asio/ip/address_v4.hpp \ + asio/ip/address_v4_iterator.hpp \ + asio/ip/address_v4_range.hpp \ + asio/ip/address_v6.hpp \ + asio/ip/address_v6_iterator.hpp \ + asio/ip/address_v6_range.hpp \ + asio/ip/bad_address_cast.hpp \ + asio/ip/basic_endpoint.hpp \ + asio/ip/basic_resolver_entry.hpp \ + asio/ip/basic_resolver.hpp \ + asio/ip/basic_resolver_iterator.hpp \ + asio/ip/basic_resolver_query.hpp \ + asio/ip/basic_resolver_results.hpp \ + asio/ip/detail/endpoint.hpp \ + asio/ip/detail/impl/endpoint.ipp \ + asio/ip/detail/socket_option.hpp \ + asio/ip/host_name.hpp \ + asio/ip/icmp.hpp \ + asio/ip/impl/address.hpp \ + asio/ip/impl/address.ipp \ + asio/ip/impl/address_v4.hpp \ + asio/ip/impl/address_v4.ipp \ + asio/ip/impl/address_v6.hpp \ + asio/ip/impl/address_v6.ipp \ + asio/ip/impl/basic_endpoint.hpp \ + asio/ip/impl/host_name.ipp \ + asio/ip/impl/network_v4.hpp \ + asio/ip/impl/network_v4.ipp \ + asio/ip/impl/network_v6.hpp \ + asio/ip/impl/network_v6.ipp \ + asio/ip/multicast.hpp \ + asio/ip/network_v4.hpp \ + asio/ip/network_v6.hpp \ + asio/ip/resolver_base.hpp \ + asio/ip/resolver_query_base.hpp \ + asio/ip/tcp.hpp \ + asio/ip/udp.hpp \ + asio/ip/unicast.hpp \ + asio/ip/v6_only.hpp \ + asio/is_applicable_property.hpp \ + asio/is_executor.hpp \ + asio/is_read_buffered.hpp \ + asio/is_write_buffered.hpp \ + asio/local/basic_endpoint.hpp \ + asio/local/connect_pair.hpp \ + asio/local/datagram_protocol.hpp \ + asio/local/detail/endpoint.hpp \ + asio/local/detail/impl/endpoint.ipp \ + asio/local/stream_protocol.hpp \ + asio/multiple_exceptions.hpp \ + asio/packaged_task.hpp \ + asio/placeholders.hpp \ + asio/posix/basic_descriptor.hpp \ + asio/posix/basic_stream_descriptor.hpp \ + asio/posix/descriptor_base.hpp \ + asio/posix/descriptor.hpp \ + asio/posix/stream_descriptor.hpp \ + asio/post.hpp \ + asio/prefer.hpp \ + asio/query.hpp \ + asio/read_at.hpp \ + asio/read.hpp \ + asio/read_until.hpp \ + asio/redirect_error.hpp \ + asio/require.hpp \ + asio/require_concept.hpp \ + asio/serial_port_base.hpp \ + asio/serial_port.hpp \ + asio/signal_set.hpp \ + asio/socket_base.hpp \ + asio/spawn.hpp \ + asio/ssl/context_base.hpp \ + asio/ssl/context.hpp \ + asio/ssl/detail/buffered_handshake_op.hpp \ + asio/ssl/detail/engine.hpp \ + asio/ssl/detail/handshake_op.hpp \ + asio/ssl/detail/impl/engine.ipp \ + asio/ssl/detail/impl/openssl_init.ipp \ + asio/ssl/detail/io.hpp \ + asio/ssl/detail/openssl_init.hpp \ + asio/ssl/detail/openssl_types.hpp \ + asio/ssl/detail/password_callback.hpp \ + asio/ssl/detail/read_op.hpp \ + asio/ssl/detail/shutdown_op.hpp \ + asio/ssl/detail/stream_core.hpp \ + asio/ssl/detail/verify_callback.hpp \ + asio/ssl/detail/write_op.hpp \ + asio/ssl/error.hpp \ + asio/ssl.hpp \ + asio/ssl/host_name_verification.hpp \ + asio/ssl/impl/context.hpp \ + asio/ssl/impl/context.ipp \ + asio/ssl/impl/error.ipp \ + asio/ssl/impl/host_name_verification.ipp \ + asio/ssl/impl/rfc2818_verification.ipp \ + asio/ssl/impl/src.hpp \ + asio/ssl/rfc2818_verification.hpp \ + asio/ssl/stream_base.hpp \ + asio/ssl/stream.hpp \ + asio/ssl/verify_context.hpp \ + asio/ssl/verify_mode.hpp \ + asio/static_thread_pool.hpp \ + asio/steady_timer.hpp \ + asio/strand.hpp \ + asio/streambuf.hpp \ + asio/system_context.hpp \ + asio/system_error.hpp \ + asio/system_executor.hpp \ + asio/system_timer.hpp \ + asio/this_coro.hpp \ + asio/thread.hpp \ + asio/thread_pool.hpp \ + asio/time_traits.hpp \ + asio/traits/bulk_execute_free.hpp \ + asio/traits/bulk_execute_member.hpp \ + asio/traits/connect_free.hpp \ + asio/traits/connect_member.hpp \ + asio/traits/equality_comparable.hpp \ + asio/traits/execute_free.hpp \ + asio/traits/execute_member.hpp \ + asio/traits/prefer_free.hpp \ + asio/traits/prefer_member.hpp \ + asio/traits/query_free.hpp \ + asio/traits/query_member.hpp \ + asio/traits/query_static_constexpr_member.hpp \ + asio/traits/require_concept_free.hpp \ + asio/traits/require_concept_member.hpp \ + asio/traits/require_free.hpp \ + asio/traits/require_member.hpp \ + asio/traits/schedule_free.hpp \ + asio/traits/schedule_member.hpp \ + asio/traits/set_done_free.hpp \ + asio/traits/set_done_member.hpp \ + asio/traits/set_error_free.hpp \ + asio/traits/set_error_member.hpp \ + asio/traits/set_value_free.hpp \ + asio/traits/set_value_member.hpp \ + asio/traits/start_free.hpp \ + asio/traits/start_member.hpp \ + asio/traits/static_query.hpp \ + asio/traits/static_require.hpp \ + asio/traits/static_require_concept.hpp \ + asio/traits/submit_free.hpp \ + asio/traits/submit_member.hpp \ + asio/ts/buffer.hpp \ + asio/ts/executor.hpp \ + asio/ts/internet.hpp \ + asio/ts/io_context.hpp \ + asio/ts/netfwd.hpp \ + asio/ts/net.hpp \ + asio/ts/socket.hpp \ + asio/ts/timer.hpp \ + asio/unyield.hpp \ + asio/use_awaitable.hpp \ + asio/use_future.hpp \ + asio/uses_executor.hpp \ + asio/version.hpp \ + asio/wait_traits.hpp \ + asio/windows/basic_object_handle.hpp \ + asio/windows/basic_overlapped_handle.hpp \ + asio/windows/basic_random_access_handle.hpp \ + asio/windows/basic_stream_handle.hpp \ + asio/windows/object_handle.hpp \ + asio/windows/overlapped_handle.hpp \ + asio/windows/overlapped_ptr.hpp \ + asio/windows/random_access_handle.hpp \ + asio/windows/stream_handle.hpp \ + asio/write_at.hpp \ + asio/write.hpp \ + asio/yield.hpp + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-nobase_includeHEADERS: $(nobase_include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-nobase_includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-nobase_includeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + cscopelist-am ctags ctags-am distclean distclean-generic \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-nobase_includeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-nobase_includeHEADERS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/asio-1.18.2/include/asio.hpp b/extern/asio-1.18.2/include/asio.hpp new file mode 100644 index 0000000..31ce82d --- /dev/null +++ b/extern/asio-1.18.2/include/asio.hpp @@ -0,0 +1,182 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_HPP +#define ASIO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/awaitable.hpp" +#include "asio/basic_datagram_socket.hpp" +#include "asio/basic_deadline_timer.hpp" +#include "asio/basic_io_object.hpp" +#include "asio/basic_raw_socket.hpp" +#include "asio/basic_seq_packet_socket.hpp" +#include "asio/basic_serial_port.hpp" +#include "asio/basic_signal_set.hpp" +#include "asio/basic_socket.hpp" +#include "asio/basic_socket_acceptor.hpp" +#include "asio/basic_socket_iostream.hpp" +#include "asio/basic_socket_streambuf.hpp" +#include "asio/basic_stream_socket.hpp" +#include "asio/basic_streambuf.hpp" +#include "asio/basic_waitable_timer.hpp" +#include "asio/bind_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/buffered_read_stream_fwd.hpp" +#include "asio/buffered_read_stream.hpp" +#include "asio/buffered_stream_fwd.hpp" +#include "asio/buffered_stream.hpp" +#include "asio/buffered_write_stream_fwd.hpp" +#include "asio/buffered_write_stream.hpp" +#include "asio/buffers_iterator.hpp" +#include "asio/co_spawn.hpp" +#include "asio/completion_condition.hpp" +#include "asio/compose.hpp" +#include "asio/connect.hpp" +#include "asio/coroutine.hpp" +#include "asio/deadline_timer.hpp" +#include "asio/defer.hpp" +#include "asio/detached.hpp" +#include "asio/dispatch.hpp" +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/execution.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/any_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/blocking_adaptation.hpp" +#include "asio/execution/bulk_execute.hpp" +#include "asio/execution/bulk_guarantee.hpp" +#include "asio/execution/connect.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/context_as.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/execution/mapping.hpp" +#include "asio/execution/occupancy.hpp" +#include "asio/execution/operation_state.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/execution/prefer_only.hpp" +#include "asio/execution/receiver.hpp" +#include "asio/execution/receiver_invocation_error.hpp" +#include "asio/execution/relationship.hpp" +#include "asio/execution/schedule.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/execution/set_value.hpp" +#include "asio/execution/start.hpp" +#include "asio/execution_context.hpp" +#include "asio/executor.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/generic/basic_endpoint.hpp" +#include "asio/generic/datagram_protocol.hpp" +#include "asio/generic/raw_protocol.hpp" +#include "asio/generic/seq_packet_protocol.hpp" +#include "asio/generic/stream_protocol.hpp" +#include "asio/handler_alloc_hook.hpp" +#include "asio/handler_continuation_hook.hpp" +#include "asio/handler_invoke_hook.hpp" +#include "asio/high_resolution_timer.hpp" +#include "asio/io_context.hpp" +#include "asio/io_context_strand.hpp" +#include "asio/io_service.hpp" +#include "asio/io_service_strand.hpp" +#include "asio/ip/address.hpp" +#include "asio/ip/address_v4.hpp" +#include "asio/ip/address_v4_iterator.hpp" +#include "asio/ip/address_v4_range.hpp" +#include "asio/ip/address_v6.hpp" +#include "asio/ip/address_v6_iterator.hpp" +#include "asio/ip/address_v6_range.hpp" +#include "asio/ip/network_v4.hpp" +#include "asio/ip/network_v6.hpp" +#include "asio/ip/bad_address_cast.hpp" +#include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" +#include "asio/ip/basic_resolver_entry.hpp" +#include "asio/ip/basic_resolver_iterator.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/host_name.hpp" +#include "asio/ip/icmp.hpp" +#include "asio/ip/multicast.hpp" +#include "asio/ip/resolver_base.hpp" +#include "asio/ip/resolver_query_base.hpp" +#include "asio/ip/tcp.hpp" +#include "asio/ip/udp.hpp" +#include "asio/ip/unicast.hpp" +#include "asio/ip/v6_only.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/is_executor.hpp" +#include "asio/is_read_buffered.hpp" +#include "asio/is_write_buffered.hpp" +#include "asio/local/basic_endpoint.hpp" +#include "asio/local/connect_pair.hpp" +#include "asio/local/datagram_protocol.hpp" +#include "asio/local/stream_protocol.hpp" +#include "asio/multiple_exceptions.hpp" +#include "asio/packaged_task.hpp" +#include "asio/placeholders.hpp" +#include "asio/posix/basic_descriptor.hpp" +#include "asio/posix/basic_stream_descriptor.hpp" +#include "asio/posix/descriptor.hpp" +#include "asio/posix/descriptor_base.hpp" +#include "asio/posix/stream_descriptor.hpp" +#include "asio/post.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/read.hpp" +#include "asio/read_at.hpp" +#include "asio/read_until.hpp" +#include "asio/redirect_error.hpp" +#include "asio/require.hpp" +#include "asio/require_concept.hpp" +#include "asio/serial_port.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/signal_set.hpp" +#include "asio/socket_base.hpp" +#include "asio/static_thread_pool.hpp" +#include "asio/steady_timer.hpp" +#include "asio/strand.hpp" +#include "asio/streambuf.hpp" +#include "asio/system_context.hpp" +#include "asio/system_error.hpp" +#include "asio/system_executor.hpp" +#include "asio/system_timer.hpp" +#include "asio/this_coro.hpp" +#include "asio/thread.hpp" +#include "asio/thread_pool.hpp" +#include "asio/time_traits.hpp" +#include "asio/use_awaitable.hpp" +#include "asio/use_future.hpp" +#include "asio/uses_executor.hpp" +#include "asio/version.hpp" +#include "asio/wait_traits.hpp" +#include "asio/windows/basic_object_handle.hpp" +#include "asio/windows/basic_overlapped_handle.hpp" +#include "asio/windows/basic_random_access_handle.hpp" +#include "asio/windows/basic_stream_handle.hpp" +#include "asio/windows/object_handle.hpp" +#include "asio/windows/overlapped_handle.hpp" +#include "asio/windows/overlapped_ptr.hpp" +#include "asio/windows/random_access_handle.hpp" +#include "asio/windows/stream_handle.hpp" +#include "asio/write.hpp" +#include "asio/write_at.hpp" + +#endif // ASIO_HPP diff --git a/extern/asio-1.18.2/include/asio/any_io_executor.hpp b/extern/asio-1.18.2/include/asio/any_io_executor.hpp new file mode 100644 index 0000000..5f2c13f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/any_io_executor.hpp @@ -0,0 +1,300 @@ +// +// any_io_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ANY_IO_EXECUTOR_HPP +#define ASIO_ANY_IO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/executor.hpp" +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/execution.hpp" +# include "asio/execution_context.hpp" +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_io_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_io_executor type is a polymorphic executor that supports the set + * of properties required by I/O objects. It is defined as the + * execution::any_executor class template parameterised as follows: + * @code execution::any_executor< + * execution::context_as_t, + * execution::blocking_t::never_t, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only + * > @endcode + */ +class any_io_executor : +#if defined(GENERATING_DOCUMENTATION) + public execution::any_executor<...> +#else // defined(GENERATING_DOCUMENTATION) + public execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +public: +#if !defined(GENERATING_DOCUMENTATION) + typedef execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > base_type; + + typedef void supportable_properties_type( + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + ); +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Default constructor. + any_io_executor() ASIO_NOEXCEPT + : base_type() + { + } + + /// Construct in an empty state. Equivalent effects to default constructor. + any_io_executor(nullptr_t) ASIO_NOEXCEPT + : base_type(nullptr_t()) + { + } + + /// Copy constructor. + any_io_executor(const any_io_executor& e) ASIO_NOEXCEPT + : base_type(static_cast(e)) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + any_io_executor(any_io_executor&& e) ASIO_NOEXCEPT + : base_type(static_cast(e)) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(execution::any_executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(OtherAnyExecutor e, + typename constraint< + conditional< + !is_same::value + && is_base_of::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target, + false_type + >::type::value + >::type = 0) + : base_type(ASIO_MOVE_CAST(OtherAnyExecutor)(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(Executor e, + typename constraint< + conditional< + !is_same::value + && !is_base_of::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::type::value + >::type = 0) + : base_type(ASIO_MOVE_CAST(Executor)(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + any_io_executor& operator=(const any_io_executor& e) ASIO_NOEXCEPT + { + base_type::operator=(static_cast(e)); + return *this; + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move assignment operator. + any_io_executor& operator=(any_io_executor&& e) ASIO_NOEXCEPT + { + base_type::operator=(static_cast(e)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + any_io_executor& operator=(nullptr_t) + { + base_type::operator=(nullptr_t()); + return *this; + } + + /// Destructor. + ~any_io_executor() + { + } + + /// Swap targets with another polymorphic wrapper. + void swap(any_io_executor& other) ASIO_NOEXCEPT + { + static_cast(*this).swap(static_cast(other)); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::require(ex, execution::blocking.possibly); @endcode + */ + template + any_io_executor require(const Property& p, + typename constraint< + traits::require_member::is_valid + >::type = 0) const + { + return static_cast(*this).require(p); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template + any_io_executor prefer(const Property& p, + typename constraint< + traits::prefer_member::is_valid + >::type = 0) const + { + return static_cast(*this).prefer(p); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <> +struct equality_comparable +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member : + query_member +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member : + require_member +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member : + prefer_member +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ANY_IO_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/associated_allocator.hpp b/extern/asio-1.18.2/include/asio/associated_allocator.hpp new file mode 100644 index 0000000..8e7a345 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/associated_allocator.hpp @@ -0,0 +1,125 @@ +// +// associated_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ASSOCIATED_ALLOCATOR_HPP +#define ASIO_ASSOCIATED_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct associated_allocator_impl +{ + typedef E type; + + static type get(const T&, const E& e) ASIO_NOEXCEPT + { + return e; + } +}; + +template +struct associated_allocator_impl::type> +{ + typedef typename T::allocator_type type; + + static type get(const T& t, const E&) ASIO_NOEXCEPT + { + return t.get_allocator(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the allocator associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Allocator shall be a type meeting the Allocator requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c a is an object of type @c + * Allocator. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Allocator requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,a) and with return type @c type. + */ +template > +struct associated_allocator +{ + /// If @c T has a nested type @c allocator_type, T::allocator_type. + /// Otherwise @c Allocator. +#if defined(GENERATING_DOCUMENTATION) + typedef see_below type; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::associated_allocator_impl::type type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c allocator_type, returns + /// t.get_allocator(). Otherwise returns @c a. + static type get(const T& t, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return detail::associated_allocator_impl::get(t, a); + } +}; + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t) + */ +template +inline typename associated_allocator::type +get_associated_allocator(const T& t) ASIO_NOEXCEPT +{ + return associated_allocator::get(t); +} + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t, a) + */ +template +inline typename associated_allocator::type +get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT +{ + return associated_allocator::get(t, a); +} + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template > +using associated_allocator_t + = typename associated_allocator::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP diff --git a/extern/asio-1.18.2/include/asio/associated_executor.hpp b/extern/asio-1.18.2/include/asio/associated_executor.hpp new file mode 100644 index 0000000..3da1a6b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/associated_executor.hpp @@ -0,0 +1,166 @@ +// +// associated_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ASSOCIATED_EXECUTOR_HPP +#define ASIO_ASSOCIATED_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct associated_executor_impl +{ + typedef void asio_associated_executor_is_unspecialised; + + typedef E type; + + static type get(const T&, const E& e = E()) ASIO_NOEXCEPT + { + return e; + } +}; + +template +struct associated_executor_impl::type> +{ + typedef typename T::executor_type type; + + static type get(const T& t, const E& = E()) ASIO_NOEXCEPT + { + return t.get_executor(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type. + */ +template +struct associated_executor +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_executor_impl +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c executor_type, T::executor_type. + /// Otherwise @c Executor. + typedef see_below type; + + /// If @c T has a nested type @c executor_type, returns + /// t.get_executor(). Otherwise returns @c ex. + static type get(const T& t, + const Executor& ex = Executor()) ASIO_NOEXCEPT; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t) ASIO_NOEXCEPT +{ + return associated_executor::get(t); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ex) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t, const Executor& ex, + typename constraint< + is_executor::value || execution::is_executor::value + >::type = 0) ASIO_NOEXCEPT +{ + return associated_executor::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ctx.get_executor()) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t, ExecutionContext& ctx, + typename constraint::value>::type = 0) ASIO_NOEXCEPT +{ + return associated_executor::get(t, ctx.get_executor()); +} + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template +using associated_executor_t = typename associated_executor::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +namespace detail { + +template +struct associated_executor_forwarding_base +{ +}; + +template +struct associated_executor_forwarding_base::asio_associated_executor_is_unspecialised, + void + >::value + >::type> +{ + typedef void asio_associated_executor_is_unspecialised; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/async_result.hpp b/extern/asio-1.18.2/include/asio/async_result.hpp new file mode 100644 index 0000000..56bdcc3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/async_result.hpp @@ -0,0 +1,582 @@ +// +// async_result.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ASYNC_RESULT_HPP +#define ASIO_ASYNC_RESULT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_HAS_CONCEPTS) \ + && defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + && defined(ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct is_completion_signature : false_type +{ +}; + +template +struct is_completion_signature : true_type +{ +}; + +template +ASIO_CONCEPT callable_with = requires(T t, Args&&... args) +{ + t(static_cast(args)...); +}; + +template +struct is_completion_handler_for : false_type +{ +}; + +template +struct is_completion_handler_for + : integral_constant)> +{ +}; + +} // namespace detail + +template +ASIO_CONCEPT completion_signature = + detail::is_completion_signature::value; + +#define ASIO_COMPLETION_SIGNATURE \ + ::asio::completion_signature + +template +ASIO_CONCEPT completion_handler_for = + detail::is_completion_signature::value + && detail::is_completion_handler_for::value; + +#define ASIO_COMPLETION_HANDLER_FOR(s) \ + ::asio::completion_handler_for + +#else // defined(ASIO_HAS_CONCEPTS) + // && defined(ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(ASIO_HAS_DECLTYPE) + +#define ASIO_COMPLETION_SIGNATURE typename +#define ASIO_COMPLETION_HANDLER_FOR(s) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + // && defined(ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(ASIO_HAS_DECLTYPE) + +/// An interface for customising the behaviour of an initiating function. +/** + * The async_result traits class is used for determining: + * + * @li the concrete completion handler type to be called at the end of the + * asynchronous operation; + * + * @li the initiating function return type; and + * + * @li how the return value of the initiating function is obtained. + * + * The trait allows the handler and return types to be determined at the point + * where the specific completion handler signature is known. + * + * This template may be specialised for user-defined completion token types. + * The primary template assumes that the CompletionToken is the completion + * handler. + */ +template +class async_result +{ +public: + /// The concrete completion handler type for the specific signature. + typedef CompletionToken completion_handler_type; + + /// The return type of the initiating function. + typedef void return_type; + + /// Construct an async result from a given handler. + /** + * When using a specalised async_result, the constructor has an opportunity + * to initialise some state associated with the completion handler, which is + * then returned from the initiating function. + */ + explicit async_result(completion_handler_type& h) + { + (void)h; + } + + /// Obtain the value to be returned from the initiating function. + return_type get() + { + } + +#if defined(GENERATING_DOCUMENTATION) + + /// Initiate the asynchronous operation that will produce the result, and + /// obtain the value to be returned from the initiating function. + template + static return_type initiate( + ASIO_MOVE_ARG(Initiation) initiation, + ASIO_MOVE_ARG(RawCompletionToken) token, + ASIO_MOVE_ARG(Args)... args); + +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + ASIO_MOVE_ARG(Initiation) initiation, + ASIO_MOVE_ARG(RawCompletionToken) token, + ASIO_MOVE_ARG(Args)... args) + { + ASIO_MOVE_CAST(Initiation)(initiation)( + ASIO_MOVE_CAST(RawCompletionToken)(token), + ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + ASIO_MOVE_ARG(Initiation) initiation, + ASIO_MOVE_ARG(RawCompletionToken) token) + { + ASIO_MOVE_CAST(Initiation)(initiation)( + ASIO_MOVE_CAST(RawCompletionToken)(token)); + } + +#define ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + static return_type initiate( \ + ASIO_MOVE_ARG(Initiation) initiation, \ + ASIO_MOVE_ARG(RawCompletionToken) token, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + ASIO_MOVE_CAST(Initiation)(initiation)( \ + ASIO_MOVE_CAST(RawCompletionToken)(token), \ + ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF) +#undef ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +private: + async_result(const async_result&) ASIO_DELETED; + async_result& operator=(const async_result&) ASIO_DELETED; +}; + +#if !defined(GENERATING_DOCUMENTATION) + +template +class async_result +{ + // Empty. +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Helper template to deduce the handler type from a CompletionToken, capture +/// a local copy of the handler, and then create an async_result for the +/// handler. +template +struct async_completion +{ + /// The real handler type to be used for the asynchronous operation. + typedef typename asio::async_result< + typename decay::type, + Signature>::completion_handler_type completion_handler_type; + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Constructor. + /** + * The constructor creates the concrete completion handler and makes the link + * between the handler and the asynchronous result. + */ + explicit async_completion(CompletionToken& token) + : completion_handler(static_cast::value, + completion_handler_type&, CompletionToken&&>::type>(token)), + result(completion_handler) + { + } +#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + explicit async_completion(typename decay::type& token) + : completion_handler(token), + result(completion_handler) + { + } + + explicit async_completion(const typename decay::type& token) + : completion_handler(token), + result(completion_handler) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// A copy of, or reference to, a real handler object. +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + typename conditional< + is_same::value, + completion_handler_type&, completion_handler_type>::type completion_handler; +#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + completion_handler_type completion_handler; +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// The result of the asynchronous operation's initiating function. + async_result::type, Signature> result; +}; + +namespace detail { + +template +struct async_result_helper + : async_result::type, Signature> +{ +}; + +struct async_result_memfns_base +{ + void initiate(); +}; + +template +struct async_result_memfns_derived + : T, async_result_memfns_base +{ +}; + +template +struct async_result_memfns_check +{ +}; + +template +char (&async_result_initiate_memfn_helper(...))[2]; + +template +char async_result_initiate_memfn_helper( + async_result_memfns_check< + void (async_result_memfns_base::*)(), + &async_result_memfns_derived::initiate>*); + +template +struct async_result_has_initiate_memfn + : integral_constant::type, Signature> + >(0)) != 1> +{ +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_RESULT_TYPE(ct, sig) \ + void_or_deduced +#elif defined(_MSC_VER) && (_MSC_VER < 1500) +# define ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::asio::detail::async_result_helper< \ + ct, sig>::return_type +#define ASIO_HANDLER_TYPE(ct, sig) \ + typename ::asio::detail::async_result_helper< \ + ct, sig>::completion_handler_type +#else +# define ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::asio::async_result< \ + typename ::asio::decay::type, sig>::return_type +#define ASIO_HANDLER_TYPE(ct, sig) \ + typename ::asio::async_result< \ + typename ::asio::decay::type, sig>::completion_handler_type +#endif + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +#elif defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +#else +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + ASIO_INITFN_RESULT_TYPE(ct, sig) +#endif + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + void_or_deduced +#elif defined(ASIO_HAS_DECLTYPE) +# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + decltype expr +#else +# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + ASIO_INITFN_RESULT_TYPE(ct, sig) +#endif + +#if defined(GENERATING_DOCUMENTATION) + +template +void_or_deduced async_initiate( + ASIO_MOVE_ARG(Initiation) initiation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken), + ASIO_MOVE_ARG(Args)... args); + +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline typename constraint< + detail::async_result_has_initiate_memfn::value, + ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, + (async_result::type, + Signature>::initiate(declval(), + declval(), + declval()...)))>::type +async_initiate(ASIO_MOVE_ARG(Initiation) initiation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + ASIO_MOVE_ARG(Args)... args) +{ + return async_result::type, + Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), + ASIO_MOVE_CAST(CompletionToken)(token), + ASIO_MOVE_CAST(Args)(args)...); +} + +template +inline typename constraint< + !detail::async_result_has_initiate_memfn::value, + ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(ASIO_MOVE_ARG(Initiation) initiation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + ASIO_MOVE_ARG(Args)... args) +{ + async_completion completion(token); + + ASIO_MOVE_CAST(Initiation)(initiation)( + ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, + Signature))(completion.completion_handler), + ASIO_MOVE_CAST(Args)(args)...); + + return completion.result.get(); +} + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline typename constraint< + detail::async_result_has_initiate_memfn::value, + ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, + (async_result::type, + Signature>::initiate(declval(), + declval())))>::type +async_initiate(ASIO_MOVE_ARG(Initiation) initiation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + return async_result::type, + Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), + ASIO_MOVE_CAST(CompletionToken)(token)); +} + +template +inline typename constraint< + !detail::async_result_has_initiate_memfn::value, + ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(ASIO_MOVE_ARG(Initiation) initiation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + async_completion completion(token); + + ASIO_MOVE_CAST(Initiation)(initiation)( + ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, + Signature))(completion.completion_handler)); + + return completion.result.get(); +} + +#define ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + inline typename constraint< \ + detail::async_result_has_initiate_memfn< \ + CompletionToken, Signature>::value, \ + ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, \ + (async_result::type, \ + Signature>::initiate(declval(), \ + declval(), \ + ASIO_VARIADIC_MOVE_DECLVAL(n))))>::type \ + async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \ + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_result::type, \ + Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), \ + ASIO_MOVE_CAST(CompletionToken)(token), \ + ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + inline typename constraint< \ + !detail::async_result_has_initiate_memfn< \ + CompletionToken, Signature>::value, \ + ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \ + async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \ + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + async_completion completion(token); \ + \ + ASIO_MOVE_CAST(Initiation)(initiation)( \ + ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, \ + Signature))(completion.completion_handler), \ + ASIO_VARIADIC_MOVE_ARGS(n)); \ + \ + return completion.result.get(); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF) +#undef ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) \ + && defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + && defined(ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct initiation_archetype +{ + template CompletionHandler> + void operator()(CompletionHandler&&) const + { + } +}; + +} // namespace detail + +template +ASIO_CONCEPT completion_token_for = + detail::is_completion_signature::value + && + requires(T&& t) + { + async_initiate(detail::initiation_archetype{}, t); + }; + +#define ASIO_COMPLETION_TOKEN_FOR(s) \ + ::asio::completion_token_for + +#else // defined(ASIO_HAS_CONCEPTS) + // && defined(ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(ASIO_HAS_DECLTYPE) + +#define ASIO_COMPLETION_TOKEN_FOR(s) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + // && defined(ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct default_completion_token_impl +{ + typedef void type; +}; + +template +struct default_completion_token_impl::type> +{ + typedef typename T::default_completion_token_type type; +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) + +/// Traits type used to determine the default completion token type associated +/// with a type (such as an executor). +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. + * + * Specialisations of this trait may provide a nested typedef @c type, which is + * a default-constructible completion token type. + */ +template +struct default_completion_token +{ + /// If @c T has a nested type @c default_completion_token_type, + /// T::default_completion_token_type. Otherwise the typedef @c type + /// is not defined. + typedef see_below type; +}; +#else +template +struct default_completion_token + : detail::default_completion_token_impl +{ +}; +#endif + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template +using default_completion_token_t = typename default_completion_token::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +#if defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \ + = typename ::asio::default_completion_token::type +#define ASIO_DEFAULT_COMPLETION_TOKEN(e) \ + = typename ::asio::default_completion_token::type() + +#else // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) +#define ASIO_DEFAULT_COMPLETION_TOKEN(e) + +#endif // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASYNC_RESULT_HPP diff --git a/extern/asio-1.18.2/include/asio/awaitable.hpp b/extern/asio-1.18.2/include/asio/awaitable.hpp new file mode 100644 index 0000000..4897049 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/awaitable.hpp @@ -0,0 +1,133 @@ +// +// awaitable.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_AWAITABLE_HPP +#define ASIO_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_STD_COROUTINE) +# include +#else // defined(ASIO_HAS_STD_COROUTINE) +# include +#endif // defined(ASIO_HAS_STD_COROUTINE) + +#include "asio/any_io_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_COROUTINE) +using std::coroutine_handle; +using std::suspend_always; +#else // defined(ASIO_HAS_STD_COROUTINE) +using std::experimental::coroutine_handle; +using std::experimental::suspend_always; +#endif // defined(ASIO_HAS_STD_COROUTINE) + +template class awaitable_thread; +template class awaitable_frame; + +} // namespace detail + +/// The return type of a coroutine or asynchronous operation. +template +class awaitable +{ +public: + /// The type of the awaited value. + typedef T value_type; + + /// The executor type that will be used for the coroutine. + typedef Executor executor_type; + + /// Default constructor. + constexpr awaitable() noexcept + : frame_(nullptr) + { + } + + /// Move constructor. + awaitable(awaitable&& other) noexcept + : frame_(std::exchange(other.frame_, nullptr)) + { + } + + /// Destructor + ~awaitable() + { + if (frame_) + frame_->destroy(); + } + + /// Checks if the awaitable refers to a future result. + bool valid() const noexcept + { + return !!frame_; + } + +#if !defined(GENERATING_DOCUMENTATION) + + // Support for co_await keyword. + bool await_ready() const noexcept + { + return false; + } + + // Support for co_await keyword. + template + void await_suspend( + detail::coroutine_handle> h) + { + frame_->push_frame(&h.promise()); + } + + // Support for co_await keyword. + T await_resume() + { + return awaitable(static_cast(*this)).frame_->get(); + } + +#endif // !defined(GENERATING_DOCUMENTATION) + +private: + template friend class detail::awaitable_thread; + template friend class detail::awaitable_frame; + + // Not copy constructible or copy assignable. + awaitable(const awaitable&) = delete; + awaitable& operator=(const awaitable&) = delete; + + // Construct the awaitable from a coroutine's frame object. + explicit awaitable(detail::awaitable_frame* a) + : frame_(a) + { + } + + detail::awaitable_frame* frame_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/awaitable.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_AWAITABLE_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_datagram_socket.hpp b/extern/asio-1.18.2/include/asio/basic_datagram_socket.hpp new file mode 100644 index 0000000..d9fba8a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_datagram_socket.hpp @@ -0,0 +1,1223 @@ +// +// basic_datagram_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_DATAGRAM_SOCKET_HPP +#define ASIO_BASIC_DATAGRAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_datagram_socket; + +#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) + +/// Provides datagram-oriented socket functionality. +/** + * The basic_datagram_socket class template provides asynchronous and blocking + * datagram-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c send_to, @c receive, @c receive_from, and @c connect + * operations are thread safe with respect to each other, if the underlying + * operating system calls are also thread safe. This means that it is permitted + * to perform concurrent calls to these synchronous operations on a single + * socket object. Other synchronous operations, such as @c open or @c close, are + * not thread safe. + */ +template +class basic_datagram_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_datagram_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_datagram_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_datagram_socket(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const endpoint_type& endpoint, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_datagram_socket from another. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + basic_datagram_socket(basic_datagram_socket&& other) ASIO_NOEXCEPT + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_datagram_socket from another. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + basic_datagram_socket& operator=(basic_datagram_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + template + basic_datagram_socket(basic_datagram_socket&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_datagram_socket& + >::type operator=(basic_datagram_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_datagram_socket() + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, buffers, flags); + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->impl_.get_service().send_to(this->impl_.get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send_to(this), handler, buffers, + destination, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send_to(this), handler, buffers, destination, flags); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, buffers, flags); + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * asio::buffer(data, size), sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_from(this), handler, buffers, + &sender_endpoint, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_from(this), handler, + buffers, &sender_endpoint, flags); + } + +private: + // Disallow copying and assignment. + basic_datagram_socket(const basic_datagram_socket&) ASIO_DELETED; + basic_datagram_socket& operator=( + const basic_datagram_socket&) ASIO_DELETED; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_send_to + { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_receive_from + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_deadline_timer.hpp b/extern/asio-1.18.2/include/asio/basic_deadline_timer.hpp new file mode 100644 index 0000000..1104c61 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_deadline_timer.hpp @@ -0,0 +1,693 @@ +// +// basic_deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_DEADLINE_TIMER_HPP +#define ASIO_BASIC_DEADLINE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include "asio/any_io_executor.hpp" +#include "asio/detail/deadline_timer_service.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/time_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides waitable timer functionality. +/** + * The basic_deadline_timer class template provides the ability to perform a + * blocking or asynchronous wait for a timer to expire. + * + * A deadline timer is always in one of two states: "expired" or "not expired". + * If the wait() or async_wait() function is called on an expired timer, the + * wait operation will complete immediately. + * + * Most applications will use the asio::deadline_timer typedef. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Examples + * Performing a blocking wait: + * @code + * // Construct a timer without setting an expiry time. + * asio::deadline_timer timer(my_context); + * + * // Set an expiry time relative to now. + * timer.expires_from_now(boost::posix_time::seconds(5)); + * + * // Wait for the timer to expire. + * timer.wait(); + * @endcode + * + * @par + * Performing an asynchronous wait: + * @code + * void handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Timer expired. + * } + * } + * + * ... + * + * // Construct a timer with an absolute expiry time. + * asio::deadline_timer timer(my_context, + * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); + * + * // Start an asynchronous wait. + * timer.async_wait(handler); + * @endcode + * + * @par Changing an active deadline_timer's expiry time + * + * Changing the expiry time of a timer while there are pending asynchronous + * waits causes those wait operations to be cancelled. To ensure that the action + * associated with the timer is performed only once, use something like this: + * used: + * + * @code + * void on_some_event() + * { + * if (my_timer.expires_from_now(seconds(5)) > 0) + * { + * // We managed to cancel the timer. Start new asynchronous wait. + * my_timer.async_wait(on_timeout); + * } + * else + * { + * // Too late, timer has already expired! + * } + * } + * + * void on_timeout(const asio::error_code& e) + * { + * if (e != asio::error::operation_aborted) + * { + * // Timer was not cancelled, take necessary action. + * } + * } + * @endcode + * + * @li The asio::basic_deadline_timer::expires_from_now() function + * cancels any pending asynchronous waits, and returns the number of + * asynchronous waits that were cancelled. If it returns 0 then you were too + * late and the wait handler has already been executed, or will soon be + * executed. If it returns 1 then the wait handler was successfully cancelled. + * + * @li If a wait handler is cancelled, the asio::error_code passed to + * it contains the value asio::error::operation_aborted. + */ +template , + typename Executor = any_io_executor> +class basic_deadline_timer +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the timer type to another executor. + template + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_deadline_timer other; + }; + + /// The time traits type. + typedef TimeTraits traits_type; + + /// The time type. + typedef typename traits_type::time_type time_type; + + /// The duration type. + typedef typename traits_type::duration_type duration_type; + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_deadline_timer(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + */ + template + explicit basic_deadline_timer(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + basic_deadline_timer(const executor_type& ex, const time_type& expiry_time) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template + basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + basic_deadline_timer(const executor_type& ex, + const duration_type& expiry_time) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template + basic_deadline_timer(ExecutionContext& context, + const duration_type& expiry_time, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_deadline_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. + */ + basic_deadline_timer(basic_deadline_timer&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_deadline_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. + */ + basic_deadline_timer& operator=(basic_deadline_timer&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_deadline_timer() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel() + { + asio::error_code ec; + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + return s; + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel(asio::error_code& ec) + { + return impl_.get_service().cancel(impl_.get_implementation(), ec); + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one() + { + asio::error_code ec; + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel_one"); + return s; + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one(asio::error_code& ec) + { + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); + } + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_type expires_at() const + { + return impl_.get_service().expires_at(impl_.get_implementation()); + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time) + { + asio::error_code ec; + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + return s; + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time, + asio::error_code& ec) + { + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + } + + /// Get the timer's expiry time relative to now. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + duration_type expires_from_now() const + { + return impl_.get_service().expires_from_now(impl_.get_implementation()); + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time) + { + asio::error_code ec; + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + return s; + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time, + asio::error_code& ec) + { + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @throws asio::system_error Thrown on failure. + */ + void wait() + { + asio::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(asio::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li The timer has expired. + * + * @li The timer was cancelled, in which case the handler is passed the error + * code asio::error::operation_aborted. + * + * @param handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, + void (asio::error_code)) + async_wait( + ASIO_MOVE_ARG(WaitHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_wait(this), handler); + } + +private: + // Disallow copying and assignment. + basic_deadline_timer(const basic_deadline_timer&) ASIO_DELETED; + basic_deadline_timer& operator=( + const basic_deadline_timer&) ASIO_DELETED; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_deadline_timer* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_deadline_timer* self_; + }; + + detail::io_object_impl< + detail::deadline_timer_service, Executor> impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_DEADLINE_TIMER_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_io_object.hpp b/extern/asio-1.18.2/include/asio/basic_io_object.hpp new file mode 100644 index 0000000..733557e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_io_object.hpp @@ -0,0 +1,290 @@ +// +// basic_io_object.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_IO_OBJECT_HPP +#define ASIO_BASIC_IO_OBJECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_HAS_MOVE) +namespace detail +{ + // Type trait used to determine whether a service supports move. + template + class service_has_move + { + private: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + + template + static auto asio_service_has_move_eval(T* t, U* u) + -> decltype(t->move_construct(*u, *u), char()); + static char (&asio_service_has_move_eval(...))[2]; + + public: + static const bool value = + sizeof(asio_service_has_move_eval( + static_cast(0), + static_cast(0))) == 1; + }; +} +#endif // defined(ASIO_HAS_MOVE) + +/// Base class for all I/O objects. +/** + * @note All I/O objects are non-copyable. However, when using C++0x, certain + * I/O objects do support move construction and move assignment. + */ +#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +template +#else +template ::value> +#endif +class basic_io_object +{ +public: + /// The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + /// The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_context& get_io_context() + { + return service_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_context& get_io_service() + { + return service_.get_io_context(); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// The type of the executor associated with the object. + typedef asio::io_context::executor_type executor_type; + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return service_.get_io_context().get_executor(); + } + +protected: + /// Construct a basic_io_object. + /** + * Performs: + * @code get_service().construct(get_implementation()); @endcode + */ + explicit basic_io_object(asio::io_context& io_context) + : service_(asio::use_service(io_context)) + { + service_.construct(implementation_); + } + +#if defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_io_object. + /** + * Performs: + * @code get_service().move_construct( + * get_implementation(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object(basic_io_object&& other); + + /// Move-assign a basic_io_object. + /** + * Performs: + * @code get_service().move_assign(get_implementation(), + * other.get_service(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object& operator=(basic_io_object&& other); + + /// Perform a converting move-construction of a basic_io_object. + template + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation); +#endif // defined(GENERATING_DOCUMENTATION) + + /// Protected destructor to prevent deletion through this type. + /** + * Performs: + * @code get_service().destroy(get_implementation()); @endcode + */ + ~basic_io_object() + { + service_.destroy(implementation_); + } + + /// Get the service associated with the I/O object. + service_type& get_service() + { + return service_; + } + + /// Get the service associated with the I/O object. + const service_type& get_service() const + { + return service_; + } + + /// Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation_; + } + + /// Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + basic_io_object(const basic_io_object&); + basic_io_object& operator=(const basic_io_object&); + + // The service associated with the I/O object. + service_type& service_; + + /// The underlying implementation of the I/O object. + implementation_type implementation_; +}; + +#if defined(ASIO_HAS_MOVE) +// Specialisation for movable objects. +template +class basic_io_object +{ +public: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + +#if !defined(ASIO_NO_DEPRECATED) + asio::io_context& get_io_context() + { + return service_->get_io_context(); + } + + asio::io_context& get_io_service() + { + return service_->get_io_context(); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + typedef asio::io_context::executor_type executor_type; + + executor_type get_executor() ASIO_NOEXCEPT + { + return service_->get_io_context().get_executor(); + } + +protected: + explicit basic_io_object(asio::io_context& io_context) + : service_(&asio::use_service(io_context)) + { + service_->construct(implementation_); + } + + basic_io_object(basic_io_object&& other) + : service_(&other.get_service()) + { + service_->move_construct(implementation_, other.implementation_); + } + + template + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation) + : service_(&asio::use_service( + other_service.get_io_context())) + { + service_->converting_move_construct(implementation_, + other_service, other_implementation); + } + + ~basic_io_object() + { + service_->destroy(implementation_); + } + + basic_io_object& operator=(basic_io_object&& other) + { + service_->move_assign(implementation_, + *other.service_, other.implementation_); + service_ = other.service_; + return *this; + } + + service_type& get_service() + { + return *service_; + } + + const service_type& get_service() const + { + return *service_; + } + + implementation_type& get_implementation() + { + return implementation_; + } + + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + basic_io_object(const basic_io_object&); + void operator=(const basic_io_object&); + + IoObjectService* service_; + implementation_type implementation_; +}; +#endif // defined(ASIO_HAS_MOVE) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_IO_OBJECT_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_raw_socket.hpp b/extern/asio-1.18.2/include/asio/basic_raw_socket.hpp new file mode 100644 index 0000000..60801e3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_raw_socket.hpp @@ -0,0 +1,1214 @@ +// +// basic_raw_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_RAW_SOCKET_HPP +#define ASIO_BASIC_RAW_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL) +#define ASIO_BASIC_RAW_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_raw_socket; + +#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL) + +/// Provides raw-oriented socket functionality. +/** + * The basic_raw_socket class template provides asynchronous and blocking + * raw-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c send_to, @c receive, @c receive_from, and @c connect + * operations are thread safe with respect to each other, if the underlying + * operating system calls are also thread safe. This means that it is permitted + * to perform concurrent calls to these synchronous operations on a single + * socket object. Other synchronous operations, such as @c open or @c close, are + * not thread safe. + */ +template +class basic_raw_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_raw_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_raw_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_raw_socket(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_raw_socket from another. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + basic_raw_socket(basic_raw_socket&& other) ASIO_NOEXCEPT + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_raw_socket from another. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + basic_raw_socket& operator=(basic_raw_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_raw_socket from a socket of another protocol + /// type. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + template + basic_raw_socket(basic_raw_socket&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_raw_socket from a socket of another protocol type. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_raw_socket& + >::type operator=(basic_raw_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_raw_socket() + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, buffers, flags); + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->impl_.get_service().send_to(this->impl_.get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send_to(this), handler, buffers, + destination, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send_to(this), handler, buffers, destination, flags); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, buffers, flags); + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_from(this), handler, buffers, + &sender_endpoint, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_from(this), handler, + buffers, &sender_endpoint, flags); + } + +private: + // Disallow copying and assignment. + basic_raw_socket(const basic_raw_socket&) ASIO_DELETED; + basic_raw_socket& operator=(const basic_raw_socket&) ASIO_DELETED; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_send_to + { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_receive_from + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_RAW_SOCKET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_seq_packet_socket.hpp b/extern/asio-1.18.2/include/asio/basic_seq_packet_socket.hpp new file mode 100644 index 0000000..684261b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_seq_packet_socket.hpp @@ -0,0 +1,768 @@ +// +// basic_seq_packet_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SEQ_PACKET_SOCKET_HPP +#define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) +#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_seq_packet_socket; + +#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) + +/// Provides sequenced packet socket functionality. +/** + * The basic_seq_packet_socket class template provides asynchronous and blocking + * sequenced packet socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c receive, and @c connect operations are thread safe + * with respect to each other, if the underlying operating system calls are + * also thread safe. This means that it is permitted to perform concurrent + * calls to these synchronous operations on a single socket object. Other + * synchronous operations, such as @c open or @c close, are not thread safe. + */ +template +class basic_seq_packet_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_seq_packet_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_seq_packet_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_seq_packet_socket(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const endpoint_type& endpoint, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_seq_packet_socket from another. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + basic_seq_packet_socket(basic_seq_packet_socket&& other) ASIO_NOEXCEPT + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from another. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + template + basic_seq_packet_socket(basic_seq_packet_socket&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_seq_packet_socket& + >::type operator=(basic_seq_packet_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_seq_packet_socket() + { + } + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block until the data has been sent successfully, or an + * until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block the data has been sent successfully, or an until + * error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. Returns 0 if an error occurred. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the sequenced packet + * socket. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, buffers, flags); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size), out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, 0, out_flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size), 0, out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. Returns 0 if an error occurred. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + return this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * packet socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_with_flags(this), handler, + buffers, socket_base::message_flags(0), &out_flags); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * data socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive( + * asio::buffer(data, size), + * 0, out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive_with_flags(this), + handler, buffers, in_flags, &out_flags); + } + +private: + // Disallow copying and assignment. + basic_seq_packet_socket(const basic_seq_packet_socket&) ASIO_DELETED; + basic_seq_packet_socket& operator=( + const basic_seq_packet_socket&) ASIO_DELETED; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_seq_packet_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_seq_packet_socket* self_; + }; + + class initiate_async_receive_with_flags + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags* out_flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive_with_flags( + self_->impl_.get_implementation(), buffers, in_flags, + *out_flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_seq_packet_socket* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_serial_port.hpp b/extern/asio-1.18.2/include/asio/basic_serial_port.hpp new file mode 100644 index 0000000..1c0c636 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_serial_port.hpp @@ -0,0 +1,907 @@ +// +// basic_serial_port.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_BASIC_SERIAL_PORT_HPP +#define ASIO_BASIC_SERIAL_PORT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/serial_port_base.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_serial_port_service.hpp" +#else +# include "asio/detail/reactive_serial_port_service.hpp" +#endif + +#if defined(ASIO_HAS_MOVE) +# include +#endif // defined(ASIO_HAS_MOVE) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides serial port functionality. +/** + * The basic_serial_port class provides a wrapper over serial port + * functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_serial_port + : public serial_port_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the serial port type to another executor. + template + struct rebind_executor + { + /// The serial port type when rebound to the specified executor. + typedef basic_serial_port other; + }; + + /// The native representation of a serial port. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_serial_port_service::native_handle_type + native_handle_type; +#else + typedef detail::reactive_serial_port_service::native_handle_type + native_handle_type; +#endif + + /// A basic_basic_serial_port is always the lowest layer. + typedef basic_serial_port lowest_layer_type; + + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + */ + explicit basic_serial_port(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + */ + template + explicit basic_serial_port(ExecutionContext& context, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + basic_serial_port(const executor_type& ex, const char* device) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + template + basic_serial_port(ExecutionContext& context, const char* device, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + basic_serial_port(const executor_type& ex, const std::string& device) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + template + basic_serial_port(ExecutionContext& context, const std::string& device, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + basic_serial_port(const executor_type& ex, + const native_handle_type& native_serial_port) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_serial_port(ExecutionContext& context, + const native_handle_type& native_serial_port, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_serial_port from another. + /** + * This constructor moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + basic_serial_port(basic_serial_port&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_serial_port from another. + /** + * This assignment operator moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + basic_serial_port& operator=(basic_serial_port&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the serial port. + /** + * This function destroys the serial port, cancelling any outstanding + * asynchronous wait operations associated with the serial port as if by + * calling @c cancel. + */ + ~basic_serial_port() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port for the specified device name. + * + * @param device The platform-specific device name. + * + * @throws asio::system_error Thrown on failure. + */ + void open(const std::string& device) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port using the given platform-specific + * device name. + * + * @param device The platform-specific device name. + * + * @param ec Set the indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID open(const std::string& device, + asio::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), device, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_serial_port) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, + asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the serial port is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native serial port representation. + /** + * This function may be used to obtain the underlying representation of the + * serial port. This is intended to allow access to native serial port + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @throws asio::system_error Thrown on failure. + */ + void send_break() + { + asio::error_code ec; + impl_.get_service().send_break(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "send_break"); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID send_break(asio::error_code& ec) + { + impl_.get_service().send_break(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + void set_option(const SettableSerialPortOption& option) + { + asio::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, + asio::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + void get_option(GettableSerialPortOption& option) const + { + asio::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, + asio::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.write_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the serial port. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the serial port. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.async_write_some( + * asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_write_some(this), handler, buffers); + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.read_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the serial port. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.async_read_some( + * asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_read_some(this), handler, buffers); + } + +private: + // Disallow copying and assignment. + basic_serial_port(const basic_serial_port&) ASIO_DELETED; + basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED; + + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_serial_port* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_serial_port* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_serial_port* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_serial_port* self_; + }; + +#if defined(ASIO_HAS_IOCP) + detail::io_object_impl impl_; +#else + detail::io_object_impl impl_; +#endif +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_SERIAL_PORT_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_signal_set.hpp b/extern/asio-1.18.2/include/asio/basic_signal_set.hpp new file mode 100644 index 0000000..2514434 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_signal_set.hpp @@ -0,0 +1,576 @@ +// +// basic_signal_set.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SIGNAL_SET_HPP +#define ASIO_BASIC_SIGNAL_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/signal_set_service.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides signal functionality. +/** + * The basic_signal_set class provides the ability to perform an asynchronous + * wait for one or more signals to occur. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Performing an asynchronous wait: + * @code + * void handler( + * const asio::error_code& error, + * int signal_number) + * { + * if (!error) + * { + * // A signal occurred. + * } + * } + * + * ... + * + * // Construct a signal set registered for process termination. + * asio::signal_set signals(my_context, SIGINT, SIGTERM); + * + * // Start an asynchronous wait for one of the signals to occur. + * signals.async_wait(handler); + * @endcode + * + * @par Queueing of signal notifications + * + * If a signal is registered with a signal_set, and the signal occurs when + * there are no waiting handlers, then the signal notification is queued. The + * next async_wait operation on that signal_set will dequeue the notification. + * If multiple notifications are queued, subsequent async_wait operations + * dequeue them one at a time. Signal notifications are dequeued in order of + * ascending signal number. + * + * If a signal number is removed from a signal_set (using the @c remove or @c + * erase member functions) then any queued notifications for that signal are + * discarded. + * + * @par Multiple registration of signals + * + * The same signal number may be registered with different signal_set objects. + * When the signal occurs, one handler is called for each signal_set object. + * + * Note that multiple registration only works for signals that are registered + * using Asio. The application must not also register a signal handler using + * functions such as @c signal() or @c sigaction(). + * + * @par Signal masking on POSIX platforms + * + * POSIX allows signals to be blocked using functions such as @c sigprocmask() + * and @c pthread_sigmask(). For signals to be delivered, programs must ensure + * that any signals registered using signal_set objects are unblocked in at + * least one thread. + */ +template +class basic_signal_set +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the signal set type to another executor. + template + struct rebind_executor + { + /// The signal set type when rebound to the specified executor. + typedef basic_signal_set other; + }; + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + */ + explicit basic_signal_set(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + */ + template + explicit basic_signal_set(ExecutionContext& context, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(ex); + * signals.add(signal_number_1); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(context); + * signals.add(signal_number_1); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(ex); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1, + int signal_number_2) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(ex); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1, + int signal_number_2, int signal_number_3) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, int signal_number_3, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Destroys the signal set. + /** + * This function destroys the signal set, cancelling any outstanding + * asynchronous wait operations associated with the signal set as if by + * calling @c cancel. + */ + ~basic_signal_set() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @throws asio::system_error Thrown on failure. + */ + void add(int signal_number) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID add(int signal_number, + asio::error_code& ec) + { + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @throws asio::system_error Thrown on failure. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + void remove(int signal_number) + { + asio::error_code ec; + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); + asio::detail::throw_error(ec, "remove"); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + ASIO_SYNC_OP_VOID remove(int signal_number, + asio::error_code& ec) + { + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @throws asio::system_error Thrown on failure. + * + * @note Removes all queued notifications. + */ + void clear() + { + asio::error_code ec; + impl_.get_service().clear(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "clear"); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes all queued notifications. + */ + ASIO_SYNC_OP_VOID clear(asio::error_code& ec) + { + impl_.get_service().clear(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @throws asio::system_error Thrown on failure. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous operation to wait for a signal to be delivered. + /** + * This function may be used to initiate an asynchronous wait against the + * signal set. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li One of the registered signals in the signal set occurs; or + * + * @li The signal set was cancelled, in which case the handler is passed the + * error code asio::error::operation_aborted. + * + * @param handler The handler to be called when the signal occurs. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * int signal_number // Indicates which signal occurred. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int)) + SignalHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler, + void (asio::error_code, int)) + async_wait( + ASIO_MOVE_ARG(SignalHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_wait(this), handler); + } + +private: + // Disallow copying and assignment. + basic_signal_set(const basic_signal_set&) ASIO_DELETED; + basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_signal_set* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(SignalHandler) handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a SignalHandler. + ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_signal_set* self_; + }; + + detail::io_object_impl impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SIGNAL_SET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_socket.hpp b/extern/asio-1.18.2/include/asio/basic_socket.hpp new file mode 100644 index 0000000..a0404ca --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_socket.hpp @@ -0,0 +1,1895 @@ +// +// basic_socket.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SOCKET_HPP +#define ASIO_BASIC_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/any_io_executor.hpp" +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/post.hpp" +#include "asio/socket_base.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_socket_service.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_socket_service.hpp" +#else +# include "asio/detail/reactive_socket_service.hpp" +#endif + +#if defined(ASIO_HAS_MOVE) +# include +#endif // defined(ASIO_HAS_MOVE) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_SOCKET_FWD_DECL) +#define ASIO_BASIC_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_socket; + +#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL) + +/// Provides socket functionality. +/** + * The basic_socket class template provides functionality that is common to both + * stream-oriented and datagram-oriented sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_socket + : public socket_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#else + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + +#if !defined(ASIO_NO_EXTENSIONS) + /// A basic_socket is always the lowest layer. + typedef basic_socket lowest_layer_type; +#endif // !defined(ASIO_NO_EXTENSIONS) + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_socket(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_socket(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const protocol_type& protocol) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const endpoint_type& endpoint) + : impl_(0, ex) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const protocol_type& protocol, + const native_handle_type& native_socket) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const protocol_type& protocol, + const native_handle_type& native_socket, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket from another. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + basic_socket(basic_socket&& other) ASIO_NOEXCEPT + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket from another. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + basic_socket& operator=(basic_socket&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All sockets have access to each other's implementations. + template + friend class basic_socket; + + /// Move-construct a basic_socket from a socket of another protocol type. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + template + basic_socket(basic_socket&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket from a socket of another protocol type. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_socket& + >::type operator=(basic_socket && other) + { + basic_socket tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + +#if !defined(ASIO_NO_EXTENSIONS) + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } +#endif // !defined(ASIO_NO_EXTENSIONS) + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * socket.open(asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * asio::error_code ec; + * socket.open(asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID open(const protocol_type& protocol, + asio::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_socket) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, + const native_handle_type& native_socket, asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the socket is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::error_code ec; + * socket.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native socket representation. + /** + * This function may be used to obtain the underlying representation of the + * socket. This is intended to allow access to native socket functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + * + * @throws asio::system_error Thrown on failure. + */ + bool at_mark() const + { + asio::error_code ec; + bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "at_mark"); + return b; + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + */ + bool at_mark(asio::error_code& ec) const + { + return impl_.get_service().at_mark(impl_.get_implementation(), ec); + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + * + * @throws asio::system_error Thrown on failure. + */ + std::size_t available() const + { + asio::error_code ec; + std::size_t s = impl_.get_service().available( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "available"); + return s; + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + */ + std::size_t available(asio::error_code& ec) const + { + return impl_.get_service().available(impl_.get_implementation(), ec); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * socket.open(asio::ip::tcp::v4()); + * socket.bind(asio::ip::tcp::endpoint( + * asio::ip::tcp::v4(), 12345)); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + asio::error_code ec; + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * socket.open(asio::ip::tcp::v4()); + * asio::error_code ec; + * socket.bind(asio::ip::tcp::endpoint( + * asio::ip::tcp::v4(), 12345), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, + asio::error_code& ec) + { + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.connect(endpoint); + * @endcode + */ + void connect(const endpoint_type& peer_endpoint) + { + asio::error_code ec; + if (!is_open()) + { + impl_.get_service().open(impl_.get_implementation(), + peer_endpoint.protocol(), ec); + asio::detail::throw_error(ec, "connect"); + } + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); + asio::detail::throw_error(ec, "connect"); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * asio::error_code ec; + * socket.connect(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint, + asio::error_code& ec) + { + if (!is_open()) + { + impl_.get_service().open(impl_.get_implementation(), + peer_endpoint.protocol(), ec); + if (ec) + { + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous connect. + /** + * This function is used to asynchronously connect a socket to the specified + * remote endpoint. The function call always returns immediately. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. Copies will be made of the endpoint object as required. + * + * @param handler The handler to be called when the connection operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void connect_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Connect succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::socket socket(my_context); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_connect(endpoint, connect_handler); + * @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + ConnectHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(ConnectHandler, + void (asio::error_code)) + async_connect(const endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(ConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + asio::error_code open_ec; + if (!is_open()) + { + const protocol_type protocol = peer_endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, open_ec); + } + + return async_initiate( + initiate_async_connect(this), handler, peer_endpoint, open_ec); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::no_delay option(true); + * socket.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + asio::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::no_delay option(true); + * asio::error_code ec; + * socket.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, + asio::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::socket::keep_alive option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + asio::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::socket::keep_alive option; + * asio::error_code ec; + * socket.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.value(); + * @endcode + */ + template + ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, + asio::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * asio::socket_base::bytes_readable @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::socket::bytes_readable command; + * socket.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + asio::error_code ec; + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * asio::socket_base::bytes_readable @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::socket::bytes_readable command; + * asio::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + asio::error_code& ec) + { + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the socket. + /** + * @returns @c true if the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + bool non_blocking() const + { + return impl_.get_service().non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @throws asio::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + void non_blocking(bool mode) + { + asio::error_code ec; + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + ASIO_SYNC_OP_VOID non_blocking( + bool mode, asio::error_code& ec) + { + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native socket implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native socket. This mode has no effect on the behaviour of the socket + * object's synchronous operations. + * + * @returns @c true if the underlying socket is in non-blocking mode and + * direct system calls may fail with asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the socket object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native socket. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + bool native_non_blocking() const + { + return impl_.get_service().native_non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @throws asio::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + void native_non_blocking(bool mode) + { + asio::error_code ec; + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, asio::error_code& ec) + { + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @returns An object that represents the local endpoint of the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + asio::error_code ec; + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(asio::error_code& ec) const + { + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @returns An object that represents the remote endpoint of the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); + * @endcode + */ + endpoint_type remote_endpoint() const + { + asio::error_code ec; + endpoint_type ep = impl_.get_service().remote_endpoint( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "remote_endpoint"); + return ep; + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the remote endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type remote_endpoint(asio::error_code& ec) const + { + return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * socket.shutdown(asio::ip::tcp::socket::shutdown_send); + * @endcode + */ + void shutdown(shutdown_type what) + { + asio::error_code ec; + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); + asio::detail::throw_error(ec, "shutdown"); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::error_code ec; + * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID shutdown(shutdown_type what, + asio::error_code& ec) + { + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * socket.wait(asio::ip::tcp::socket::wait_read); + * @endcode + */ + void wait(wait_type w) + { + asio::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), w, ec); + asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::error_code ec; + * socket.wait(asio::ip::tcp::socket::wait_read, ec); + * @endcode + */ + ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), w, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void wait_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::socket socket(my_context); + * ... + * socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler); + * @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, + void (asio::error_code)) + async_wait(wait_type w, + ASIO_MOVE_ARG(WaitHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_wait(this), handler, w); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_socket() + { + } + +#if defined(ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service, Executor> impl_; +#elif defined(ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service, Executor> impl_; +#endif + +private: + // Disallow copying and assignment. + basic_socket(const basic_socket&) ASIO_DELETED; + basic_socket& operator=(const basic_socket&) ASIO_DELETED; + + class initiate_async_connect + { + public: + typedef Executor executor_type; + + explicit initiate_async_connect(basic_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ConnectHandler) handler, + const endpoint_type& peer_endpoint, + const asio::error_code& open_ec) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ConnectHandler. + ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; + + if (open_ec) + { + asio::post(self_->impl_.get_executor(), + asio::detail::bind_handler( + ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec)); + } + else + { + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_connect( + self_->impl_.get_implementation(), peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + } + + private: + basic_socket* self_; + }; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SOCKET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_socket_acceptor.hpp b/extern/asio-1.18.2/include/asio/basic_socket_acceptor.hpp new file mode 100644 index 0000000..2633f8c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_socket_acceptor.hpp @@ -0,0 +1,2508 @@ +// +// basic_socket_acceptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SOCKET_ACCEPTOR_HPP +#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_socket_service.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_socket_service.hpp" +#else +# include "asio/detail/reactive_socket_service.hpp" +#endif + +#if defined(ASIO_HAS_MOVE) +# include +#endif // defined(ASIO_HAS_MOVE) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) +#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_socket_acceptor; + +#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) + +/// Provides the ability to accept new connections. +/** + * The basic_socket_acceptor class template is used for accepting new socket + * connections. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c accept operations are thread safe, if the underlying + * operating system calls are also thread safe. This means that it is permitted + * to perform concurrent calls to synchronous @c accept operations on a single + * socket object. Other synchronous operations, such as @c open or @c close, are + * not thread safe. + * + * @par Example + * Opening a socket acceptor with the SO_REUSEADDR option enabled: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); + * acceptor.open(endpoint.protocol()); + * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ +template +class basic_socket_acceptor + : public socket_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the acceptor type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket_acceptor other; + }; + + /// The native representation of an acceptor. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#else + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + */ + explicit basic_socket_acceptor(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + */ + template + explicit basic_socket_acceptor(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws asio::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(my_context); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ + basic_socket_acceptor(const executor_type& ex, + const endpoint_type& endpoint, bool reuse_addr = true) + : impl_(0, ex) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + impl_.get_service().set_option(impl_.get_implementation(), + socket_base::reuse_address(true), ec); + asio::detail::throw_error(ec, "set_option"); + } + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + impl_.get_service().listen(impl_.get_implementation(), + socket_base::max_listen_connections, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws asio::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(my_context); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ + template + basic_socket_acceptor(ExecutionContext& context, + const endpoint_type& endpoint, bool reuse_addr = true, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + impl_.get_service().set_option(impl_.get_implementation(), + socket_base::reuse_address(true), ec); + asio::detail::throw_error(ec, "set_option"); + } + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + impl_.get_service().listen(impl_.get_implementation(), + socket_base::max_listen_connections, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket_acceptor(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_acceptor) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_acceptor, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_acceptor from another. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + basic_socket_acceptor(basic_socket_acceptor&& other) ASIO_NOEXCEPT + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket_acceptor from another. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + basic_socket_acceptor& operator=(basic_socket_acceptor&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All socket acceptors have access to each other's implementations. + template + friend class basic_socket_acceptor; + + /// Move-construct a basic_socket_acceptor from an acceptor of another + /// protocol type. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + template + basic_socket_acceptor(basic_socket_acceptor&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket_acceptor from an acceptor of another protocol + /// type. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_socket_acceptor& + >::type operator=(basic_socket_acceptor&& other) + { + basic_socket_acceptor tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the acceptor. + /** + * This function destroys the acceptor, cancelling any outstanding + * asynchronous operations associated with the acceptor as if by calling + * @c cancel. + */ + ~basic_socket_acceptor() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * acceptor.open(asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * asio::error_code ec; + * acceptor.open(asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID open(const protocol_type& protocol, + asio::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_acceptor) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, + const native_handle_type& native_acceptor, asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the acceptor is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * acceptor.bind(endpoint); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + asio::error_code ec; + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * asio::error_code ec; + * acceptor.bind(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, + asio::error_code& ec) + { + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @throws asio::system_error Thrown on failure. + */ + void listen(int backlog = socket_base::max_listen_connections) + { + asio::error_code ec; + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::error_code ec; + * acceptor.listen(asio::socket_base::max_listen_connections, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID listen(int backlog, asio::error_code& ec) + { + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::error_code ec; + * acceptor.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native acceptor representation. + /** + * This function may be used to obtain the underlying representation of the + * acceptor. This is intended to allow access to native acceptor functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * asio::socket_base::reuse_address + * asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::reuse_address option(true); + * acceptor.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + asio::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * asio::socket_base::reuse_address + * asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::reuse_address option(true); + * asio::error_code ec; + * acceptor.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, + asio::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::reuse_address option; + * acceptor.get_option(option); + * bool is_set = option.get(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + asio::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::reuse_address option; + * asio::error_code ec; + * acceptor.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.get(); + * @endcode + */ + template + ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, + asio::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::non_blocking_io command(true); + * socket.io_control(command); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + asio::error_code ec; + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::acceptor::non_blocking_io command(true); + * asio::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + asio::error_code& ec) + { + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the acceptor. + /** + * @returns @c true if the acceptor's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + bool non_blocking() const + { + return impl_.get_service().non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @throws asio::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + void non_blocking(bool mode) + { + asio::error_code ec; + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + ASIO_SYNC_OP_VOID non_blocking( + bool mode, asio::error_code& ec) + { + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native acceptor. This mode has no effect on the behaviour of the acceptor + * object's synchronous operations. + * + * @returns @c true if the underlying acceptor is in non-blocking mode and + * direct system calls may fail with asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the acceptor object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native acceptor. + */ + bool native_non_blocking() const + { + return impl_.get_service().native_non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @throws asio::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + */ + void native_non_blocking(bool mode) + { + asio::error_code ec; + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + */ + ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, asio::error_code& ec) + { + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @returns An object that represents the local endpoint of the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + asio::error_code ec; + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the acceptor. + * Returns a default-constructed endpoint object if an error occurred and the + * error handler did not throw an exception. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(asio::error_code& ec) const + { + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); + } + + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.wait(asio::ip::tcp::acceptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + asio::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), w, ec); + asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::error_code ec; + * acceptor.wait(asio::ip::tcp::acceptor::wait_read, ec); + * @endcode + */ + ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), w, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the acceptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for an acceptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void wait_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_wait( + * asio::ip::tcp::acceptor::wait_read, + * wait_handler); + * @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, + void (asio::error_code)) + async_wait(wait_type w, + ASIO_MOVE_ARG(WaitHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_wait(this), handler, w); + } + +#if !defined(ASIO_NO_EXTENSIONS) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(my_context); + * acceptor.accept(socket); + * @endcode + */ + template + void accept(basic_socket& peer, + typename constraint< + is_convertible::value + >::type = 0) + { + asio::error_code ec; + impl_.get_service().accept(impl_.get_implementation(), + peer, static_cast(0), ec); + asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(my_context); + * asio::error_code ec; + * acceptor.accept(socket, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + ASIO_SYNC_OP_VOID accept( + basic_socket& peer, asio::error_code& ec, + typename constraint< + is_convertible::value + >::type = 0) + { + impl_.get_service().accept(impl_.get_implementation(), + peer, static_cast(0), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket. The function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(my_context); + * acceptor.async_accept(socket, accept_handler); + * @endcode + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, + void (asio::error_code)) + async_accept(basic_socket& peer, + ASIO_MOVE_ARG(AcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), + typename constraint< + is_convertible::value + >::type = 0) + { + return async_initiate( + initiate_async_accept(this), handler, + &peer, static_cast(0)); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(my_context); + * asio::ip::tcp::endpoint endpoint; + * acceptor.accept(socket, endpoint); + * @endcode + */ + template + void accept(basic_socket& peer, + endpoint_type& peer_endpoint) + { + asio::error_code ec; + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(my_context); + * asio::ip::tcp::endpoint endpoint; + * asio::error_code ec; + * acceptor.accept(socket, endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + ASIO_SYNC_OP_VOID accept(basic_socket& peer, + endpoint_type& peer_endpoint, asio::error_code& ec) + { + impl_.get_service().accept( + impl_.get_implementation(), peer, &peer_endpoint, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket, and additionally obtain the endpoint of the remote peer. The + * function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, + void (asio::error_code)) + async_accept(basic_socket& peer, + endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(AcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_accept(this), handler, &peer, &peer_endpoint); + } +#endif // !defined(ASIO_NO_EXTENSIONS) + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + typename Protocol::socket::template rebind_executor::other + accept() + { + asio::error_code ec; + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept(ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket::template rebind_executor::other + accept(asio::error_code& ec) + { + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor::other peer + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(accept_handler); + * @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template + rebind_executor::other)) + async_accept( + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate::other)>( + initiate_async_move_accept(this), handler, + impl_.get_executor(), static_cast(0), + static_cast::other*>(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly + * accepted socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + asio::error_code ec; + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + { + asio::error_code ec; + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, asio::error_code& ec, + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, asio::error_code& ec, + typename constraint< + is_convertible::value + >::type = 0) + { + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(my_context2, accept_handler); + * @endcode + */ + template ::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)) + async_accept(const Executor1& ex, + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + typedef typename Protocol::socket::template rebind_executor< + Executor1>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(this), handler, + ex, static_cast(0), + static_cast(0)); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(my_context2, accept_handler); + * @endcode + */ + template ::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) + async_accept(ExecutionContext& context, + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), + typename constraint< + is_convertible::value + >::type = 0) + { + typedef typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(this), handler, + context.get_executor(), static_cast(0), + static_cast(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket(acceptor.accept(endpoint)); + * @endcode + */ + typename Protocol::socket::template rebind_executor::other + accept(endpoint_type& peer_endpoint) + { + asio::error_code ec; + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket::template rebind_executor::other + accept(endpoint_type& peer_endpoint, asio::error_code& ec) + { + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor::other peer + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(endpoint, accept_handler); + * @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template + rebind_executor::other)) + async_accept(endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate::other)>( + initiate_async_move_accept(this), handler, + impl_.get_executor(), &peer_endpoint, + static_cast::other*>(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint)); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, endpoint_type& peer_endpoint, + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + asio::error_code ec; + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint)); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, endpoint_type& peer_endpoint, + typename constraint< + is_convertible::value + >::type = 0) + { + asio::error_code ec; + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const executor_type& ex, + endpoint_type& peer_endpoint, asio::error_code& ec, + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + endpoint_type& peer_endpoint, asio::error_code& ec, + typename constraint< + is_convertible::value + >::type = 0) + { + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(my_context2, endpoint, accept_handler); + * @endcode + */ + template ::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)) + async_accept(const Executor1& ex, endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), + typename constraint< + is_executor::value + || execution::is_executor::value + >::type = 0) + { + typedef typename Protocol::socket::template rebind_executor< + Executor1>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(this), handler, + ex, &peer_endpoint, + static_cast(0)); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(my_context2, endpoint, accept_handler); + * @endcode + */ + template ::other)) MoveAcceptHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) + async_accept(ExecutionContext& context, + endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(MoveAcceptHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), + typename constraint< + is_convertible::value + >::type = 0) + { + typedef typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(this), handler, + context.get_executor(), &peer_endpoint, + static_cast(0)); + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +private: + // Disallow copying and assignment. + basic_socket_acceptor(const basic_socket_acceptor&) ASIO_DELETED; + basic_socket_acceptor& operator=( + const basic_socket_acceptor&) ASIO_DELETED; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + + class initiate_async_accept + { + public: + typedef Executor executor_type; + + explicit initiate_async_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(AcceptHandler) handler, + basic_socket* peer, + endpoint_type* peer_endpoint) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a AcceptHandler. + ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_accept( + self_->impl_.get_implementation(), *peer, peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + + class initiate_async_move_accept + { + public: + typedef Executor executor_type; + + explicit initiate_async_move_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(MoveAcceptHandler) handler, + const Executor1& peer_ex, endpoint_type* peer_endpoint, Socket*) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a MoveAcceptHandler. + ASIO_MOVE_ACCEPT_HANDLER_CHECK( + MoveAcceptHandler, handler, Socket) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_move_accept( + self_->impl_.get_implementation(), peer_ex, peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + +#if defined(ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service, Executor> impl_; +#elif defined(ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service, Executor> impl_; +#endif +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_socket_iostream.hpp b/extern/asio-1.18.2/include/asio/basic_socket_iostream.hpp new file mode 100644 index 0000000..b6fd888 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_socket_iostream.hpp @@ -0,0 +1,407 @@ +// +// basic_socket_iostream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SOCKET_IOSTREAM_HPP +#define ASIO_BASIC_SOCKET_IOSTREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_IOSTREAM) + +#include +#include +#include "asio/basic_socket_streambuf.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +# include "asio/detail/variadic_templates.hpp" + +// A macro that should expand to: +// template +// explicit basic_socket_iostream(T1 x1, ..., Tn xn) +// : std::basic_iostream( +// &this->detail::socket_iostream_base< +// Protocol, Clock, WaitTraits>::streambuf_) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define ASIO_PRIVATE_CTR_DEF(n) \ + template \ + explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + : std::basic_iostream( \ + &this->detail::socket_iostream_base< \ + Protocol, Clock, WaitTraits>::streambuf_) \ + { \ + this->setf(std::ios_base::unitbuf); \ + if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +// A macro that should expand to: +// template +// void connect(T1 x1, ..., Tn xn) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define ASIO_PRIVATE_CONNECT_DEF(n) \ + template \ + void connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + { \ + if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// A separate base class is used to ensure that the streambuf is initialised +// prior to the basic_socket_iostream's basic_iostream base class. +template +class socket_iostream_base +{ +protected: + socket_iostream_base() + { + } + +#if defined(ASIO_HAS_MOVE) + socket_iostream_base(socket_iostream_base&& other) + : streambuf_(std::move(other.streambuf_)) + { + } + + socket_iostream_base(basic_stream_socket s) + : streambuf_(std::move(s)) + { + } + + socket_iostream_base& operator=(socket_iostream_base&& other) + { + streambuf_ = std::move(other.streambuf_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) + + basic_socket_streambuf streambuf_; +}; + +} // namespace detail + +#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) +#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL + +// Forward declaration with defaulted arguments. +template > +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits > +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +class basic_socket_iostream; + +#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) + +/// Iostream interface for a socket. +#if defined(GENERATING_DOCUMENTATION) +template > +#else // defined(GENERATING_DOCUMENTATION) +template +#endif // defined(GENERATING_DOCUMENTATION) +class basic_socket_iostream + : private detail::socket_iostream_base, + public std::basic_iostream +{ +private: + // These typedefs are intended keep this class's implementation independent + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef WaitTraits traits_helper; +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef detail::chrono_time_traits traits_helper; +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The clock type. + typedef Clock clock_type; + +#if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + + /// The time type. + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; + + /// The duration type. + typedef typename WaitTraits::duration duration; +#else +# if !defined(ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_type; + typedef typename traits_helper::duration_type duration_type; +# endif // !defined(ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; +#endif + + /// Construct a basic_socket_iostream without establishing a connection. + basic_socket_iostream() + : std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_iostream from the supplied socket. + explicit basic_socket_iostream(basic_stream_socket s) + : detail::socket_iostream_base< + Protocol, Clock, WaitTraits>(std::move(s)), + std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + } + +#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \ + || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_iostream from another. + basic_socket_iostream(basic_socket_iostream&& other) + : detail::socket_iostream_base< + Protocol, Clock, WaitTraits>(std::move(other)), + std::basic_iostream(std::move(other)) + { + this->set_rdbuf(&this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_); + } + + /// Move-assign a basic_socket_iostream from another. + basic_socket_iostream& operator=(basic_socket_iostream&& other) + { + std::basic_iostream::operator=(std::move(other)); + detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::operator=(std::move(other)); + return *this; + } +#endif // defined(ASIO_HAS_STD_IOSTREAM_MOVE) + // || defined(GENERATING_DOCUMENTATION) +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection to an endpoint corresponding to a resolver query. + /** + * This constructor automatically establishes a connection based on the + * supplied resolver query parameters. The arguments are used to construct + * a resolver query object. + */ + template + explicit basic_socket_iostream(T1 t1, ..., TN tn); +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + template + explicit basic_socket_iostream(T... x) + : std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + if (rdbuf()->connect(x...) == 0) + this->setstate(std::ios_base::failbit); + } +#else + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CTR_DEF) +#endif + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection to an endpoint corresponding to a resolver query. + /** + * This function automatically establishes a connection based on the supplied + * resolver query parameters. The arguments are used to construct a resolver + * query object. + */ + template + void connect(T1 t1, ..., TN tn); +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + template + void connect(T... x) + { + if (rdbuf()->connect(x...) == 0) + this->setstate(std::ios_base::failbit); + } +#else + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF) +#endif + + /// Close the connection. + void close() + { + if (rdbuf()->close() == 0) + this->setstate(std::ios_base::failbit); + } + + /// Return a pointer to the underlying streambuf. + basic_socket_streambuf* rdbuf() const + { + return const_cast*>( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_); + } + + /// Get a reference to the underlying socket. + basic_socket& socket() + { + return rdbuf()->socket(); + } + + /// Get the last error associated with the stream. + /** + * @return An \c error_code corresponding to the last error from the stream. + * + * @par Example + * To print the error associated with a failure to establish a connection: + * @code tcp::iostream s("www.boost.org", "http"); + * if (!s) + * { + * std::cout << "Error: " << s.error().message() << std::endl; + * } @endcode + */ + const asio::error_code& error() const + { + return rdbuf()->error(); + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute + /// time. + /** + * @return An absolute time value representing the stream's expiry time. + */ + time_point expires_at() const + { + return rdbuf()->expires_at(); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the stream's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream's expiry time. + */ + time_point expiry() const + { + return rdbuf()->expiry(); + } + + /// Set the stream's expiry time as an absolute time. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the stream. + */ + void expires_at(const time_point& expiry_time) + { + rdbuf()->expires_at(expiry_time); + } + + /// Set the stream's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + rdbuf()->expires_after(expiry_time); + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now. + /** + * @return A relative time value representing the stream's expiry time. + */ + duration expires_from_now() const + { + return rdbuf()->expires_from_now(); + } + + /// (Deprecated: Use expires_after().) Set the stream's expiry time relative + /// to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_from_now(const duration& expiry_time) + { + rdbuf()->expires_from_now(expiry_time); + } +#endif // !defined(ASIO_NO_DEPRECATED) + +private: + // Disallow copying and assignment. + basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED; + basic_socket_iostream& operator=( + const basic_socket_iostream&) ASIO_DELETED; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) +# undef ASIO_PRIVATE_CTR_DEF +# undef ASIO_PRIVATE_CONNECT_DEF +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(ASIO_NO_IOSTREAM) + +#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_socket_streambuf.hpp b/extern/asio-1.18.2/include/asio/basic_socket_streambuf.hpp new file mode 100644 index 0000000..11efcce --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_socket_streambuf.hpp @@ -0,0 +1,687 @@ +// +// basic_socket_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_SOCKET_STREAMBUF_HPP +#define ASIO_BASIC_SOCKET_STREAMBUF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_IOSTREAM) + +#include +#include +#include "asio/basic_socket.hpp" +#include "asio/basic_stream_socket.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/io_context.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +# include "asio/detail/deadline_timer_service.hpp" +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +# include "asio/steady_timer.hpp" +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +# include "asio/detail/variadic_templates.hpp" + +// A macro that should expand to: +// template +// basic_socket_streambuf* connect(T1 x1, ..., Tn xn) +// { +// init_buffers(); +// typedef typename Protocol::resolver resolver_type; +// resolver_type resolver(socket().get_executor()); +// connect_to_endpoints( +// resolver.resolve(x1, ..., xn, ec_)); +// return !ec_ ? this : 0; +// } +// This macro should only persist within this file. + +# define ASIO_PRIVATE_CONNECT_DEF(n) \ + template \ + basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + { \ + init_buffers(); \ + typedef typename Protocol::resolver resolver_type; \ + resolver_type resolver(socket().get_executor()); \ + connect_to_endpoints( \ + resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \ + return !ec_ ? this : 0; \ + } \ + /**/ + +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// A separate base class is used to ensure that the io_context member is +// initialised prior to the basic_socket_streambuf's basic_socket base class. +class socket_streambuf_io_context +{ +protected: + socket_streambuf_io_context(io_context* ctx) + : default_io_context_(ctx) + { + } + + shared_ptr default_io_context_; +}; + +// A separate base class is used to ensure that the dynamically allocated +// buffers are constructed prior to the basic_socket_streambuf's basic_socket +// base class. This makes moving the socket is the last potentially throwing +// step in the streambuf's move constructor, giving the constructor a strong +// exception safety guarantee. +class socket_streambuf_buffers +{ +protected: + socket_streambuf_buffers() + : get_buffer_(buffer_size), + put_buffer_(buffer_size) + { + } + + enum { buffer_size = 512 }; + std::vector get_buffer_; + std::vector put_buffer_; +}; + +} // namespace detail + +#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) +#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL + +// Forward declaration with defaulted arguments. +template > +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits > +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +class basic_socket_streambuf; + +#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) + +/// Iostream streambuf for a socket. +#if defined(GENERATING_DOCUMENTATION) +template > +#else // defined(GENERATING_DOCUMENTATION) +template +#endif // defined(GENERATING_DOCUMENTATION) +class basic_socket_streambuf + : public std::streambuf, + private detail::socket_streambuf_io_context, + private detail::socket_streambuf_buffers, +#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + private basic_socket +#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + public basic_socket +#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +{ +private: + // These typedefs are intended keep this class's implementation independent + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef WaitTraits traits_helper; +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef detail::chrono_time_traits traits_helper; +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The clock type. + typedef Clock clock_type; + +#if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + + /// The time type. + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; + + /// The duration type. + typedef typename WaitTraits::duration duration; +#else +# if !defined(ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_type; + typedef typename traits_helper::duration_type duration_type; +# endif // !defined(ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; +#endif + + /// Construct a basic_socket_streambuf without establishing a connection. + basic_socket_streambuf() + : detail::socket_streambuf_io_context(new io_context), + basic_socket(*default_io_context_), + expiry_time_(max_expiry_time()) + { + init_buffers(); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_streambuf from the supplied socket. + explicit basic_socket_streambuf(basic_stream_socket s) + : detail::socket_streambuf_io_context(0), + basic_socket(std::move(s)), + expiry_time_(max_expiry_time()) + { + init_buffers(); + } + + /// Move-construct a basic_socket_streambuf from another. + basic_socket_streambuf(basic_socket_streambuf&& other) + : detail::socket_streambuf_io_context(other), + basic_socket(std::move(other.socket())), + ec_(other.ec_), + expiry_time_(other.expiry_time_) + { + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = asio::error_code(); + other.expiry_time_ = max_expiry_time(); + other.init_buffers(); + } + + /// Move-assign a basic_socket_streambuf from another. + basic_socket_streambuf& operator=(basic_socket_streambuf&& other) + { + this->close(); + socket() = std::move(other.socket()); + detail::socket_streambuf_io_context::operator=(other); + ec_ = other.ec_; + expiry_time_ = other.expiry_time_; + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = asio::error_code(); + other.expiry_time_ = max_expiry_time(); + other.put_buffer_.resize(buffer_size); + other.init_buffers(); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor flushes buffered data. + virtual ~basic_socket_streambuf() + { + if (pptr() != pbase()) + overflow(traits_type::eof()); + } + + /// Establish a connection. + /** + * This function establishes a connection to the specified endpoint. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* connect(const endpoint_type& endpoint) + { + init_buffers(); + ec_ = asio::error_code(); + this->connect_to_endpoints(&endpoint, &endpoint + 1); + return !ec_ ? this : 0; + } + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection. + /** + * This function automatically establishes a connection based on the supplied + * resolver query parameters. The arguments are used to construct a resolver + * query object. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + template + basic_socket_streambuf* connect(T1 t1, ..., TN tn); +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + template + basic_socket_streambuf* connect(T... x) + { + init_buffers(); + typedef typename Protocol::resolver resolver_type; + resolver_type resolver(socket().get_executor()); + connect_to_endpoints(resolver.resolve(x..., ec_)); + return !ec_ ? this : 0; + } +#else + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF) +#endif + + /// Close the connection. + /** + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* close() + { + sync(); + socket().close(ec_); + if (!ec_) + init_buffers(); + return !ec_ ? this : 0; + } + + /// Get a reference to the underlying socket. + basic_socket& socket() + { + return *this; + } + + /// Get the last error associated with the stream buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + const asio::error_code& error() const + { + return ec_; + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use error().) Get the last error associated with the stream + /// buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + const asio::error_code& puberror() const + { + return error(); + } + + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an + /// absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_point expires_at() const + { + return expiry_time_; + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the stream buffer's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_point expiry() const + { + return expiry_time_; + } + + /// Set the stream buffer's expiry time as an absolute time. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the stream. + */ + void expires_at(const time_point& expiry_time) + { + expiry_time_ = expiry_time; + } + + /// Set the stream buffer's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative + /// to now. + /** + * @return A relative time value representing the stream buffer's expiry time. + */ + duration expires_from_now() const + { + return traits_helper::subtract(expires_at(), traits_helper::now()); + } + + /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time + /// relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_from_now(const duration& expiry_time) + { + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); + } +#endif // !defined(ASIO_NO_DEPRECATED) + +protected: + int_type underflow() + { +#if defined(ASIO_WINDOWS_RUNTIME) + ec_ = asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(ASIO_WINDOWS_RUNTIME) + if (gptr() != egptr()) + return traits_type::eof(); + + for (;;) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = asio::error::timed_out; + return traits_type::eof(); + } + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter + bufs(asio::buffer(get_buffer_) + putback_max); + detail::signed_size_type bytes = detail::socket_ops::recv( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); + + // Check if operation succeeded. + if (bytes > 0) + { + setg(&get_buffer_[0], &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max + bytes); + return traits_type::to_int_type(*gptr()); + } + + // Check for EOF. + if (bytes == 0) + { + ec_ = asio::error::eof; + return traits_type::eof(); + } + + // Operation failed. + if (ec_ != asio::error::would_block + && ec_ != asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_read( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); + } +#endif // defined(ASIO_WINDOWS_RUNTIME) + } + + int_type overflow(int_type c) + { +#if defined(ASIO_WINDOWS_RUNTIME) + ec_ = asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(ASIO_WINDOWS_RUNTIME) + char_type ch = traits_type::to_char_type(c); + + // Determine what needs to be sent. + const_buffer output_buffer; + if (put_buffer_.empty()) + { + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); // Nothing to do. + output_buffer = asio::buffer(&ch, sizeof(char_type)); + } + else + { + output_buffer = asio::buffer(pbase(), + (pptr() - pbase()) * sizeof(char_type)); + } + + while (output_buffer.size() > 0) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = asio::error::timed_out; + return traits_type::eof(); + } + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter< + const_buffer, const_buffer> bufs(output_buffer); + detail::signed_size_type bytes = detail::socket_ops::send( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); + + // Check if operation succeeded. + if (bytes > 0) + { + output_buffer += static_cast(bytes); + continue; + } + + // Operation failed. + if (ec_ != asio::error::would_block + && ec_ != asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_write( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); + } + + if (!put_buffer_.empty()) + { + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); + + // If the new character is eof then our work here is done. + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + + // Add the new character to the output buffer. + *pptr() = ch; + pbump(1); + } + + return c; +#endif // defined(ASIO_WINDOWS_RUNTIME) + } + + int sync() + { + return overflow(traits_type::eof()); + } + + std::streambuf* setbuf(char_type* s, std::streamsize n) + { + if (pptr() == pbase() && s == 0 && n == 0) + { + put_buffer_.clear(); + setp(0, 0); + sync(); + return this; + } + + return 0; + } + +private: + // Disallow copying and assignment. + basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED; + basic_socket_streambuf& operator=( + const basic_socket_streambuf&) ASIO_DELETED; + + void init_buffers() + { + setg(&get_buffer_[0], + &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max); + + if (put_buffer_.empty()) + setp(0, 0); + else + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); + } + + int timeout() const + { + int64_t msec = traits_helper::to_posix_duration( + traits_helper::subtract(expiry_time_, + traits_helper::now())).total_milliseconds(); + if (msec > (std::numeric_limits::max)()) + msec = (std::numeric_limits::max)(); + else if (msec < 0) + msec = 0; + return static_cast(msec); + } + + template + void connect_to_endpoints(const EndpointSequence& endpoints) + { + this->connect_to_endpoints(endpoints.begin(), endpoints.end()); + } + + template + void connect_to_endpoints(EndpointIterator begin, EndpointIterator end) + { +#if defined(ASIO_WINDOWS_RUNTIME) + ec_ = asio::error::operation_not_supported; +#else // defined(ASIO_WINDOWS_RUNTIME) + if (ec_) + return; + + ec_ = asio::error::not_found; + for (EndpointIterator i = begin; i != end; ++i) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = asio::error::timed_out; + return; + } + + // Close and reopen the socket. + typename Protocol::endpoint ep(*i); + socket().close(ec_); + socket().open(ep.protocol(), ec_); + if (ec_) + continue; + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::socket_ops::connect(socket().native_handle(), + ep.data(), ep.size(), ec_); + + // Check if operation succeeded. + if (!ec_) + return; + + // Operation failed. + if (ec_ != asio::error::in_progress + && ec_ != asio::error::would_block) + continue; + + // Wait for socket to become ready. + if (detail::socket_ops::poll_connect( + socket().native_handle(), timeout(), ec_) < 0) + continue; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (detail::socket_ops::getsockopt(socket().native_handle(), 0, + SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_) + == detail::socket_error_retval) + return; + + // Check the result of the connect operation. + ec_ = asio::error_code(connect_error, + asio::error::get_system_category()); + if (!ec_) + return; + } +#endif // defined(ASIO_WINDOWS_RUNTIME) + } + + // Helper function to get the maximum expiry time. + static time_point max_expiry_time() + { +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + return boost::posix_time::pos_infin; +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + return (time_point::max)(); +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + } + + enum { putback_max = 8 }; + asio::error_code ec_; + time_point expiry_time_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) +# undef ASIO_PRIVATE_CONNECT_DEF +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(ASIO_NO_IOSTREAM) + +#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_stream_socket.hpp b/extern/asio-1.18.2/include/asio/basic_stream_socket.hpp new file mode 100644 index 0000000..c622c85 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_stream_socket.hpp @@ -0,0 +1,1060 @@ +// +// basic_stream_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_STREAM_SOCKET_HPP +#define ASIO_BASIC_STREAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/async_result.hpp" +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_stream_socket; + +#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) + +/// Provides stream-oriented socket functionality. +/** + * The basic_stream_socket class template provides asynchronous and blocking + * stream-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c receive, and @c connect operations are thread safe + * with respect to each other, if the underlying operating system calls are + * also thread safe. This means that it is permitted to perform concurrent + * calls to these synchronous operations on a single socket object. Other + * synchronous operations, such as @c open or @c close, are not thread safe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class basic_stream_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_stream_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream socket without opening it. The socket + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_stream_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream socket without opening it. The socket + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_stream_socket(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, const protocol_type& protocol, + typename constraint< + is_convertible::value, + defaulted_constraint + >::type = defaulted_constraint()) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename constraint< + is_convertible::value + >::type = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_stream_socket from another. + /** + * This constructor moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + basic_stream_socket(basic_stream_socket&& other) ASIO_NOEXCEPT + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_stream_socket from another. + /** + * This assignment operator moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + basic_stream_socket& operator=(basic_stream_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_stream_socket from a socket of another protocol + /// type. + /** + * This constructor moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + template + basic_stream_socket(basic_stream_socket&& other, + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_stream_socket from a socket of another protocol type. + /** + * This assignment operator moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value + && is_convertible::value, + basic_stream_socket& + >::type operator=(basic_stream_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_stream_socket() + { + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. Returns 0 if an error occurred. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, buffers, flags); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. Returns 0 if an error occurred. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref async_read function if you need to ensure + * that the requested amount of data is received before the asynchronous + * operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref async_read function if you need to ensure + * that the requested amount of data is received before the asynchronous + * operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, buffers, flags); + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the socket. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * socket.write_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the socket. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_write_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_send(this), handler, + buffers, socket_base::message_flags(0)); + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * socket.read_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_read_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_receive(this), handler, + buffers, socket_base::message_flags(0)); + } + +private: + // Disallow copying and assignment. + basic_stream_socket(const basic_stream_socket&) ASIO_DELETED; + basic_stream_socket& operator=(const basic_stream_socket&) ASIO_DELETED; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_stream_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_stream_socket* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_socket* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_STREAM_SOCKET_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_streambuf.hpp b/extern/asio-1.18.2/include/asio/basic_streambuf.hpp new file mode 100644 index 0000000..3e0c6e4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_streambuf.hpp @@ -0,0 +1,452 @@ +// +// basic_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_STREAMBUF_HPP +#define ASIO_BASIC_STREAMBUF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_IOSTREAM) + +#include +#include +#include +#include +#include +#include "asio/basic_streambuf_fwd.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Automatically resizable buffer class based on std::streambuf. +/** + * The @c basic_streambuf class is derived from @c std::streambuf to associate + * the streambuf's input and output sequences with one or more character + * arrays. These character arrays are internal to the @c basic_streambuf + * object, but direct access to the array elements is provided to permit them + * to be used efficiently with I/O operations. Characters written to the output + * sequence of a @c basic_streambuf object are appended to the input sequence + * of the same object. + * + * The @c basic_streambuf class's public interface is intended to permit the + * following implementation strategies: + * + * @li A single contiguous character array, which is reallocated as necessary + * to accommodate changes in the size of the character sequence. This is the + * implementation approach currently used in Asio. + * + * @li A sequence of one or more character arrays, where each array is of the + * same size. Additional character array objects are appended to the sequence + * to accommodate changes in the size of the character sequence. + * + * @li A sequence of one or more character arrays of varying sizes. Additional + * character array objects are appended to the sequence to accommodate changes + * in the size of the character sequence. + * + * The constructor for basic_streambuf accepts a @c size_t argument specifying + * the maximum of the sum of the sizes of the input sequence and output + * sequence. During the lifetime of the @c basic_streambuf object, the following + * invariant holds: + * @code size() <= max_size()@endcode + * Any member function that would, if successful, cause the invariant to be + * violated shall throw an exception of class @c std::length_error. + * + * The constructor for @c basic_streambuf takes an Allocator argument. A copy + * of this argument is used for any memory allocation performed, by the + * constructor and by all member functions, during the lifetime of each @c + * basic_streambuf object. + * + * @par Examples + * Writing directly from an streambuf to a socket: + * @code + * asio::streambuf b; + * std::ostream os(&b); + * os << "Hello, World!\n"; + * + * // try sending some data in input sequence + * size_t n = sock.send(b.data()); + * + * b.consume(n); // sent data is removed from input sequence + * @endcode + * + * Reading from a socket directly into a streambuf: + * @code + * asio::streambuf b; + * + * // reserve 512 bytes in output sequence + * asio::streambuf::mutable_buffers_type bufs = b.prepare(512); + * + * size_t n = sock.receive(bufs); + * + * // received data is "committed" from output sequence to input sequence + * b.commit(n); + * + * std::istream is(&b); + * std::string s; + * is >> s; + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +template > +#else +template +#endif +class basic_streambuf + : public std::streambuf, + private noncopyable +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The type used to represent the input sequence as a list of buffers. + typedef implementation_defined const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef implementation_defined mutable_buffers_type; +#else + typedef ASIO_CONST_BUFFER const_buffers_type; + typedef ASIO_MUTABLE_BUFFER mutable_buffers_type; +#endif + + /// Construct a basic_streambuf object. + /** + * Constructs a streambuf with the specified maximum size. The initial size + * of the streambuf's input sequence is 0. + */ + explicit basic_streambuf( + std::size_t maximum_size = (std::numeric_limits::max)(), + const Allocator& allocator = Allocator()) + : max_size_(maximum_size), + buffer_(allocator) + { + std::size_t pend = (std::min)(max_size_, buffer_delta); + buffer_.resize((std::max)(pend, 1)); + setg(&buffer_[0], &buffer_[0], &buffer_[0]); + setp(&buffer_[0], &buffer_[0] + pend); + } + + /// Get the size of the input sequence. + /** + * @returns The size of the input sequence. The value is equal to that + * calculated for @c s in the following code: + * @code + * size_t s = 0; + * const_buffers_type bufs = data(); + * const_buffers_type::const_iterator i = bufs.begin(); + * while (i != bufs.end()) + * { + * const_buffer buf(*i++); + * s += buf.size(); + * } + * @endcode + */ + std::size_t size() const ASIO_NOEXCEPT + { + return pptr() - gptr(); + } + + /// Get the maximum size of the basic_streambuf. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the current capacity of the basic_streambuf. + /** + * @returns The current total capacity of the streambuf, i.e. for both the + * input sequence and output sequence. + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return buffer_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing all character arrays in the + * input sequence. + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ + const_buffers_type data() const ASIO_NOEXCEPT + { + return asio::buffer(asio::const_buffer(gptr(), + (pptr() - gptr()) * sizeof(char_type))); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n characters, + * reallocating character array objects as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing character array objects + * at the start of the output sequence such that the sum of the buffer sizes + * is @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + reserve(n); + return asio::buffer(asio::mutable_buffer( + pptr(), n * sizeof(char_type))); + } + + /// Move characters from the output sequence to the input sequence. + /** + * Appends @c n characters from the start of the output sequence to the input + * sequence. The beginning of the output sequence is advanced by @c n + * characters. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + n = std::min(n, epptr() - pptr()); + pbump(static_cast(n)); + setg(eback(), gptr(), pptr()); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + if (egptr() < pptr()) + setg(&buffer_[0], gptr(), pptr()); + if (gptr() + n > pptr()) + n = pptr() - gptr(); + gbump(static_cast(n)); + } + +protected: + enum { buffer_delta = 128 }; + + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::underflow(). + */ + int_type underflow() + { + if (gptr() < pptr()) + { + setg(&buffer_[0], gptr(), pptr()); + return traits_type::to_int_type(*gptr()); + } + else + { + return traits_type::eof(); + } + } + + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::overflow(), + * with the specialisation that @c std::length_error is thrown if appending + * the character to the input sequence would require the condition + * size() > max_size() to be true. + */ + int_type overflow(int_type c) + { + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + if (pptr() == epptr()) + { + std::size_t buffer_size = pptr() - gptr(); + if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta) + { + reserve(max_size_ - buffer_size); + } + else + { + reserve(buffer_delta); + } + } + + *pptr() = traits_type::to_char_type(c); + pbump(1); + return c; + } + + return traits_type::not_eof(c); + } + + void reserve(std::size_t n) + { + // Get current stream positions as offsets. + std::size_t gnext = gptr() - &buffer_[0]; + std::size_t pnext = pptr() - &buffer_[0]; + std::size_t pend = epptr() - &buffer_[0]; + + // Check if there is already enough space in the put area. + if (n <= pend - pnext) + { + return; + } + + // Shift existing contents of get area to start of buffer. + if (gnext > 0) + { + pnext -= gnext; + std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); + } + + // Ensure buffer is large enough to hold at least the specified size. + if (n > pend - pnext) + { + if (n <= max_size_ && pnext <= max_size_ - n) + { + pend = pnext + n; + buffer_.resize((std::max)(pend, 1)); + } + else + { + std::length_error ex("asio::streambuf too long"); + asio::detail::throw_exception(ex); + } + } + + // Update stream positions. + setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); + setp(&buffer_[0] + pnext, &buffer_[0] + pend); + } + +private: + std::size_t max_size_; + std::vector buffer_; + + // Helper function to get the preferred size for reading data. + friend std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) + { + return std::min( + std::max(512, sb.buffer_.capacity() - sb.size()), + std::min(max_size, sb.max_size() - sb.size())); + } +}; + +/// Adapts basic_streambuf to the dynamic buffer sequence type requirements. +#if defined(GENERATING_DOCUMENTATION) +template > +#else +template +#endif +class basic_streambuf_ref +{ +public: + /// The type used to represent the input sequence as a list of buffers. + typedef typename basic_streambuf::const_buffers_type + const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef typename basic_streambuf::mutable_buffers_type + mutable_buffers_type; + + /// Construct a basic_streambuf_ref for the given basic_streambuf object. + explicit basic_streambuf_ref(basic_streambuf& sb) + : sb_(sb) + { + } + + /// Copy construct a basic_streambuf_ref. + basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT + : sb_(other.sb_) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a basic_streambuf_ref. + basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT + : sb_(other.sb_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const ASIO_NOEXCEPT + { + return sb_.size(); + } + + /// Get the maximum size of the dynamic buffer. + std::size_t max_size() const ASIO_NOEXCEPT + { + return sb_.max_size(); + } + + /// Get the current capacity of the dynamic buffer. + std::size_t capacity() const ASIO_NOEXCEPT + { + return sb_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + const_buffers_type data() const ASIO_NOEXCEPT + { + return sb_.data(); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + mutable_buffers_type prepare(std::size_t n) + { + return sb_.prepare(n); + } + + /// Move bytes from the output sequence to the input sequence. + void commit(std::size_t n) + { + return sb_.commit(n); + } + + /// Remove characters from the input sequence. + void consume(std::size_t n) + { + return sb_.consume(n); + } + +private: + basic_streambuf& sb_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_NO_IOSTREAM) + +#endif // ASIO_BASIC_STREAMBUF_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_streambuf_fwd.hpp b/extern/asio-1.18.2/include/asio/basic_streambuf_fwd.hpp new file mode 100644 index 0000000..5856c96 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_streambuf_fwd.hpp @@ -0,0 +1,36 @@ +// +// basic_streambuf_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_STREAMBUF_FWD_HPP +#define ASIO_BASIC_STREAMBUF_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_IOSTREAM) + +#include + +namespace asio { + +template > +class basic_streambuf; + +template > +class basic_streambuf_ref; + +} // namespace asio + +#endif // !defined(ASIO_NO_IOSTREAM) + +#endif // ASIO_BASIC_STREAMBUF_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/basic_waitable_timer.hpp b/extern/asio-1.18.2/include/asio/basic_waitable_timer.hpp new file mode 100644 index 0000000..417b818 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/basic_waitable_timer.hpp @@ -0,0 +1,811 @@ +// +// basic_waitable_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BASIC_WAITABLE_TIMER_HPP +#define ASIO_BASIC_WAITABLE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/any_io_executor.hpp" +#include "asio/detail/chrono_time_traits.hpp" +#include "asio/detail/deadline_timer_service.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/wait_traits.hpp" + +#if defined(ASIO_HAS_MOVE) +# include +#endif // defined(ASIO_HAS_MOVE) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) +#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL + +// Forward declaration with defaulted arguments. +template , + typename Executor = any_io_executor> +class basic_waitable_timer; + +#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) + +/// Provides waitable timer functionality. +/** + * The basic_waitable_timer class template provides the ability to perform a + * blocking or asynchronous wait for a timer to expire. + * + * A waitable timer is always in one of two states: "expired" or "not expired". + * If the wait() or async_wait() function is called on an expired timer, the + * wait operation will complete immediately. + * + * Most applications will use one of the asio::steady_timer, + * asio::system_timer or asio::high_resolution_timer typedefs. + * + * @note This waitable timer functionality is for use with the C++11 standard + * library's @c <chrono> facility, or with the Boost.Chrono library. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Examples + * Performing a blocking wait (C++11): + * @code + * // Construct a timer without setting an expiry time. + * asio::steady_timer timer(my_context); + * + * // Set an expiry time relative to now. + * timer.expires_after(std::chrono::seconds(5)); + * + * // Wait for the timer to expire. + * timer.wait(); + * @endcode + * + * @par + * Performing an asynchronous wait (C++11): + * @code + * void handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Timer expired. + * } + * } + * + * ... + * + * // Construct a timer with an absolute expiry time. + * asio::steady_timer timer(my_context, + * std::chrono::steady_clock::now() + std::chrono::seconds(60)); + * + * // Start an asynchronous wait. + * timer.async_wait(handler); + * @endcode + * + * @par Changing an active waitable timer's expiry time + * + * Changing the expiry time of a timer while there are pending asynchronous + * waits causes those wait operations to be cancelled. To ensure that the action + * associated with the timer is performed only once, use something like this: + * used: + * + * @code + * void on_some_event() + * { + * if (my_timer.expires_after(seconds(5)) > 0) + * { + * // We managed to cancel the timer. Start new asynchronous wait. + * my_timer.async_wait(on_timeout); + * } + * else + * { + * // Too late, timer has already expired! + * } + * } + * + * void on_timeout(const asio::error_code& e) + * { + * if (e != asio::error::operation_aborted) + * { + * // Timer was not cancelled, take necessary action. + * } + * } + * @endcode + * + * @li The asio::basic_waitable_timer::expires_after() function + * cancels any pending asynchronous waits, and returns the number of + * asynchronous waits that were cancelled. If it returns 0 then you were too + * late and the wait handler has already been executed, or will soon be + * executed. If it returns 1 then the wait handler was successfully cancelled. + * + * @li If a wait handler is cancelled, the asio::error_code passed to + * it contains the value asio::error::operation_aborted. + */ +template +class basic_waitable_timer +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the timer type to another executor. + template + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_waitable_timer other; + }; + + /// The clock type. + typedef Clock clock_type; + + /// The duration type of the clock. + typedef typename clock_type::duration duration; + + /// The time point type of the clock. + typedef typename clock_type::time_point time_point; + + /// The wait traits type. + typedef WaitTraits traits_type; + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_waitable_timer(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor object that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + basic_waitable_timer(const executor_type& ex, const time_point& expiry_time) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + const time_point& expiry_time, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + basic_waitable_timer(const executor_type& ex, const duration& expiry_time) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_after"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + const duration& expiry_time, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_after"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + basic_waitable_timer(basic_waitable_timer&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + basic_waitable_timer& operator=(basic_waitable_timer&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All timers have access to each other's implementations. + template + friend class basic_waitable_timer; + + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + template + basic_waitable_timer( + basic_waitable_timer&& other, + typename constraint< + is_convertible::value + >::type = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + template + typename constraint< + is_convertible::value, + basic_waitable_timer& + >::type operator=(basic_waitable_timer&& other) + { + basic_waitable_timer tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_waitable_timer() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel() + { + asio::error_code ec; + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + return s; + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancel any asynchronous + /// operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel(asio::error_code& ec) + { + return impl_.get_service().cancel(impl_.get_implementation(), ec); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one() + { + asio::error_code ec; + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel_one"); + return s; + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancels one asynchronous + /// operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one(asio::error_code& ec) + { + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); + } + + /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute + /// time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expires_at() const + { + return impl_.get_service().expires_at(impl_.get_implementation()); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expiry() const + { + return impl_.get_service().expiry(impl_.get_implementation()); + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_point& expiry_time) + { + asio::error_code ec; + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + return s; + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as + /// an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_point& expiry_time, + asio::error_code& ec) + { + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_after() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_after(const duration& expiry_time) + { + asio::error_code ec; + std::size_t s = impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_after"); + return s; + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + duration expires_from_now() const + { + return impl_.get_service().expires_from_now(impl_.get_implementation()); + } + + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration& expiry_time) + { + asio::error_code ec; + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + return s; + } + + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration& expiry_time, + asio::error_code& ec) + { + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @throws asio::system_error Thrown on failure. + */ + void wait() + { + asio::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(asio::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li The timer has expired. + * + * @li The timer was cancelled, in which case the handler is passed the error + * code asio::error::operation_aborted. + * + * @param handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, + void (asio::error_code)) + async_wait( + ASIO_MOVE_ARG(WaitHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return async_initiate( + initiate_async_wait(this), handler); + } + +private: + // Disallow copying and assignment. + basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED; + basic_waitable_timer& operator=( + const basic_waitable_timer&) ASIO_DELETED; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_waitable_timer* self) + : self_(self) + { + } + + executor_type get_executor() const ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_waitable_timer* self_; + }; + + detail::io_object_impl< + detail::deadline_timer_service< + detail::chrono_time_traits >, + executor_type > impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_WAITABLE_TIMER_HPP diff --git a/extern/asio-1.18.2/include/asio/bind_executor.hpp b/extern/asio-1.18.2/include/asio/bind_executor.hpp new file mode 100644 index 0000000..2762003 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/bind_executor.hpp @@ -0,0 +1,575 @@ +// +// bind_executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BIND_EXECUTOR_HPP +#define ASIO_BIND_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/async_result.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" +#include "asio/uses_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper to automatically define nested typedef result_type. + +template +struct executor_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template +struct executor_binder_result_type::type> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template +struct executor_binder_argument_type {}; + +template +struct executor_binder_argument_type::type> +{ + typedef typename T::argument_type argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template +struct executor_binder_argument_types {}; + +template +struct executor_binder_argument_types::type> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +// Helper to perform uses_executor construction of the target type, if +// required. + +template +class executor_binder_base; + +template +class executor_binder_base +{ +protected: + template + executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) + : executor_(ASIO_MOVE_CAST(E)(e)), + target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +template +class executor_binder_base +{ +protected: + template + executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) + : executor_(ASIO_MOVE_CAST(E)(e)), + target_(ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +// Helper to enable SFINAE on zero-argument operator() below. + +template +struct executor_binder_result_of0 +{ + typedef void type; +}; + +template +struct executor_binder_result_of0::type>::type> +{ + typedef typename result_of::type type; +}; + +} // namespace detail + +/// A call wrapper type to bind an executor of type @c Executor to an object of +/// type @c T. +template +class executor_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::executor_binder_result_type, + public detail::executor_binder_argument_type, + public detail::executor_binder_argument_types, + private detail::executor_binder_base< + T, Executor, uses_executor::value> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated executor. + typedef Executor executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct an executor wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template + executor_binder(executor_arg_t, const executor_type& e, + ASIO_MOVE_ARG(U) u) + : base_type(e, ASIO_MOVE_CAST(U)(u)) + { + } + + /// Copy constructor. + executor_binder(const executor_binder& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder& other) + : base_type(e, other.get()) + { + } + + /// Construct a copy of a different executor wrapper type. + /** + * This constructor is only valid if the @c Executor type is constructible + * from type @c OtherExecutor, and the type @c T is constructible from type + * @c U. + */ + template + executor_binder(const executor_binder& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy of a different executor wrapper type, but specify a + /// different executor. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder& other) + : base_type(e, other.get()) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Move constructor. + executor_binder(executor_binder&& other) + : base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()), + ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct the target object, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + executor_binder&& other) + : base_type(e, ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct from a different executor wrapper type. + template + executor_binder(executor_binder&& other) + : base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()), + ASIO_MOVE_CAST(U)(other.get())) + { + } + + /// Move construct from a different executor wrapper type, but specify a + /// different executor. + template + executor_binder(executor_arg_t, const executor_type& e, + executor_binder&& other) + : base_type(e, ASIO_MOVE_CAST(U)(other.get())) + { + } + +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~executor_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain the associated executor. + executor_type get_executor() const ASIO_NOEXCEPT + { + return this->executor_; + } + +#if defined(GENERATING_DOCUMENTATION) + + template auto operator()(Args&& ...); + template auto operator()(Args&& ...) const; + +#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) + + /// Forwarding function call operator. + template + typename result_of::type operator()( + ASIO_MOVE_ARG(Args)... args) + { + return this->target_(ASIO_MOVE_CAST(Args)(args)...); + } + + /// Forwarding function call operator. + template + typename result_of::type operator()( + ASIO_MOVE_ARG(Args)... args) const + { + return this->target_(ASIO_MOVE_CAST(Args)(args)...); + } + +#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typename detail::executor_binder_result_of0::type operator()() + { + return this->target_(); + } + + typename detail::executor_binder_result_of0::type operator()() const + { + return this->target_(); + } + +#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template \ + typename result_of::type operator()( \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + typename result_of::type operator()( \ + ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typedef typename detail::executor_binder_result_type::result_type_or_void + result_type_or_void; + + result_type_or_void operator()() + { + return this->target_(); + } + + result_type_or_void operator()() const + { + return this->target_(); + } + +#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template \ + result_type_or_void operator()( \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + result_type_or_void operator()( \ + ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + +private: + typedef detail::executor_binder_base::value> base_type; +}; + +/// Associate an object of type @c T with an executor of type @c Executor. +template +inline executor_binder::type, Executor> +bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t, + typename constraint< + is_executor::value || execution::is_executor::value + >::type = 0) +{ + return executor_binder::type, Executor>( + executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t)); +} + +/// Associate an object of type @c T with an execution context's executor. +template +inline executor_binder::type, + typename ExecutionContext::executor_type> +bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t, + typename constraint::value>::type = 0) +{ + return executor_binder::type, + typename ExecutionContext::executor_type>( + executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct uses_executor, Executor> + : true_type {}; + +template +class async_result, Signature> +{ +public: + typedef executor_binder< + typename async_result::completion_handler_type, Executor> + completion_handler_type; + + typedef typename async_result::return_type return_type; + + explicit async_result(executor_binder& b) + : target_(b.get()) + { + } + + return_type get() + { + return target_.get(); + } + +private: + async_result(const async_result&) ASIO_DELETED; + async_result& operator=(const async_result&) ASIO_DELETED; + + async_result target_; +}; + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const executor_binder& b, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(b.get(), a); + } +}; + +template +struct associated_executor, Executor1> +{ + typedef Executor type; + + static type get(const executor_binder& b, + const Executor1& = Executor1()) ASIO_NOEXCEPT + { + return b.get_executor(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BIND_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/buffer.hpp b/extern/asio-1.18.2/include/asio/buffer.hpp new file mode 100644 index 0000000..32848dc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffer.hpp @@ -0,0 +1,2496 @@ +// +// buffer.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFER_HPP +#define ASIO_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include +#include +#include +#include +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/string_view.hpp" +#include "asio/detail/throw_exception.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1700) +# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) +# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# define ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_HAS_ITERATOR_DEBUGGING) +#endif // defined(ASIO_MSVC) && (ASIO_MSVC >= 1700) + +#if defined(__GNUC__) +# if defined(_GLIBCXX_DEBUG) +# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# define ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_GLIBCXX_DEBUG) +#endif // defined(__GNUC__) + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) +# include "asio/detail/functional.hpp" +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + +#if defined(ASIO_HAS_BOOST_WORKAROUND) +# include +# if !defined(__clang__) +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +# define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND +# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +# elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND +# endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#endif // defined(ASIO_HAS_BOOST_WORKAROUND) + +#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) +# include "asio/detail/type_traits.hpp" +#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class mutable_buffer; +class const_buffer; + +/// Holds a buffer that can be modified. +/** + * The mutable_buffer class provides a safe representation of a buffer that can + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code asio::mutable_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast(b1.data()); + * @endcode + * + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. + */ +class mutable_buffer +{ +public: + /// Construct an empty buffer. + mutable_buffer() ASIO_NOEXCEPT + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + mutable_buffer(void* data, std::size_t size) ASIO_NOEXCEPT + : data_(data), + size_(size) + { + } + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffer(void* data, std::size_t size, + asio::detail::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const asio::detail::function& get_debug_check() const + { + return debug_check_; + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + + /// Get a pointer to the beginning of the memory range. + void* data() const ASIO_NOEXCEPT + { +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + + /// Get the size of the memory range. + std::size_t size() const ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + mutable_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast(data_) + offset; + size_ -= offset; + return *this; + } + +private: + void* data_; + std::size_t size_; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + asio::detail::function debug_check_; +#endif // ASIO_ENABLE_BUFFER_DEBUGGING +}; + +#if !defined(ASIO_NO_DEPRECATED) + +/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that +/// it meets the requirements of the MutableBufferSequence concept. +class mutable_buffers_1 + : public mutable_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Construct to represent a given memory range. + mutable_buffers_1(void* data, std::size_t size) ASIO_NOEXCEPT + : mutable_buffer(data, size) + { + } + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffers_1(void* data, std::size_t size, + asio::detail::function debug_check) + : mutable_buffer(data, size, debug_check) + { + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + + /// Construct to represent a single modifiable buffer. + explicit mutable_buffers_1(const mutable_buffer& b) ASIO_NOEXCEPT + : mutable_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const ASIO_NOEXCEPT + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const ASIO_NOEXCEPT + { + return begin() + 1; + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Holds a buffer that cannot be modified. +/** + * The const_buffer class provides a safe representation of a buffer that cannot + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code asio::const_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * const unsigned char* p1 = static_cast(b1.data()); + * @endcode + * + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. + */ +class const_buffer +{ +public: + /// Construct an empty buffer. + const_buffer() ASIO_NOEXCEPT + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + const_buffer(const void* data, std::size_t size) ASIO_NOEXCEPT + : data_(data), + size_(size) + { + } + + /// Construct a non-modifiable buffer from a modifiable one. + const_buffer(const mutable_buffer& b) ASIO_NOEXCEPT + : data_(b.data()), + size_(b.size()) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , debug_check_(b.get_debug_check()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + { + } + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffer(const void* data, std::size_t size, + asio::detail::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const asio::detail::function& get_debug_check() const + { + return debug_check_; + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + + /// Get a pointer to the beginning of the memory range. + const void* data() const ASIO_NOEXCEPT + { +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + + /// Get the size of the memory range. + std::size_t size() const ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + const_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast(data_) + offset; + size_ -= offset; + return *this; + } + +private: + const void* data_; + std::size_t size_; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + asio::detail::function debug_check_; +#endif // ASIO_ENABLE_BUFFER_DEBUGGING +}; + +#if !defined(ASIO_NO_DEPRECATED) + +/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so +/// that it meets the requirements of the ConstBufferSequence concept. +class const_buffers_1 + : public const_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef const_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const const_buffer* const_iterator; + + /// Construct to represent a given memory range. + const_buffers_1(const void* data, std::size_t size) ASIO_NOEXCEPT + : const_buffer(data, size) + { + } + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffers_1(const void* data, std::size_t size, + asio::detail::function debug_check) + : const_buffer(data, size, debug_check) + { + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + + /// Construct to represent a single non-modifiable buffer. + explicit const_buffers_1(const const_buffer& b) ASIO_NOEXCEPT + : const_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const ASIO_NOEXCEPT + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const ASIO_NOEXCEPT + { + return begin() + 1; + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +/// (Deprecated: Use the socket/descriptor wait() and async_wait() member +/// functions.) An implementation of both the ConstBufferSequence and +/// MutableBufferSequence concepts to represent a null buffer sequence. +class null_buffers +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Get a random-access iterator to the first element. + const_iterator begin() const ASIO_NOEXCEPT + { + return &buf_; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const ASIO_NOEXCEPT + { + return &buf_; + } + +private: + mutable_buffer buf_; +}; + +/** @defgroup buffer_sequence_begin asio::buffer_sequence_begin + * + * @brief The asio::buffer_sequence_begin function returns an iterator + * pointing to the first element in a buffer sequence. + */ +/*@{*/ + +/// Get an iterator to the first element in a buffer sequence. +template +inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b, + typename constraint< + is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)); +} + +/// Get an iterator to the first element in a buffer sequence. +template +inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b, + typename constraint< + is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)); +} + +#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to the first element in a buffer sequence. +template +inline auto buffer_sequence_begin(C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT -> decltype(c.begin()) +{ + return c.begin(); +} + +/// Get an iterator to the first element in a buffer sequence. +template +inline auto buffer_sequence_begin(const C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT -> decltype(c.begin()) +{ + return c.begin(); +} + +#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template +inline typename C::iterator buffer_sequence_begin(C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return c.begin(); +} + +template +inline typename C::const_iterator buffer_sequence_begin(const C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return c.begin(); +} + +#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/** @defgroup buffer_sequence_end asio::buffer_sequence_end + * + * @brief The asio::buffer_sequence_end function returns an iterator + * pointing to one past the end element in a buffer sequence. + */ +/*@{*/ + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b, + typename constraint< + is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)) + 1; +} + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline const const_buffer* buffer_sequence_end(const ConstBuffer& b, + typename constraint< + is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)) + 1; +} + +#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline auto buffer_sequence_end(C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT -> decltype(c.end()) +{ + return c.end(); +} + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline auto buffer_sequence_end(const C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT -> decltype(c.end()) +{ + return c.end(); +} + +#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template +inline typename C::iterator buffer_sequence_end(C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return c.end(); +} + +template +inline typename C::const_iterator buffer_sequence_end(const C& c, + typename constraint< + !is_convertible::value + && !is_convertible::value + >::type = 0) ASIO_NOEXCEPT +{ + return c.end(); +} + +#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +namespace detail { + +// Tag types used to select appropriately optimised overloads. +struct one_buffer {}; +struct multiple_buffers {}; + +// Helper trait to detect single buffers. +template +struct buffer_sequence_cardinality : + conditional< + is_same::value +#if !defined(ASIO_NO_DEPRECATED) + || is_same::value + || is_same::value +#endif // !defined(ASIO_NO_DEPRECATED) + || is_same::value, + one_buffer, multiple_buffers>::type {}; + +template +inline std::size_t buffer_size(one_buffer, + Iterator begin, Iterator) ASIO_NOEXCEPT +{ + return const_buffer(*begin).size(); +} + +template +inline std::size_t buffer_size(multiple_buffers, + Iterator begin, Iterator end) ASIO_NOEXCEPT +{ + std::size_t total_buffer_size = 0; + + Iterator iter = begin; + for (; iter != end; ++iter) + { + const_buffer b(*iter); + total_buffer_size += b.size(); + } + + return total_buffer_size; +} + +} // namespace detail + +/// Get the total number of bytes in a buffer sequence. +/** + * The @c buffer_size function determines the total size of all buffers in the + * buffer sequence, as if computed as follows: + * + * @code size_t total_size = 0; + * auto i = asio::buffer_sequence_begin(buffers); + * auto end = asio::buffer_sequence_end(buffers); + * for (; i != end; ++i) + * { + * const_buffer b(*i); + * total_size += b.size(); + * } + * return total_size; @endcode + * + * The @c BufferSequence template parameter may meet either of the @c + * ConstBufferSequence or @c MutableBufferSequence type requirements. + */ +template +inline std::size_t buffer_size(const BufferSequence& b) ASIO_NOEXCEPT +{ + return detail::buffer_size( + detail::buffer_sequence_cardinality(), + asio::buffer_sequence_begin(b), + asio::buffer_sequence_end(b)); +} + +#if !defined(ASIO_NO_DEPRECATED) + +/** @defgroup buffer_cast asio::buffer_cast + * + * @brief (Deprecated: Use the @c data() member function.) The + * asio::buffer_cast function is used to obtain a pointer to the + * underlying memory region associated with a buffer. + * + * @par Examples: + * + * To access the memory of a non-modifiable buffer, use: + * @code asio::const_buffer b1 = ...; + * const unsigned char* p1 = asio::buffer_cast(b1); + * @endcode + * + * To access the memory of a modifiable buffer, use: + * @code asio::mutable_buffer b2 = ...; + * unsigned char* p2 = asio::buffer_cast(b2); + * @endcode + * + * The asio::buffer_cast function permits violations of type safety, so + * uses of it in application code should be carefully considered. + */ +/*@{*/ + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +template +inline PointerToPodType buffer_cast(const mutable_buffer& b) ASIO_NOEXCEPT +{ + return static_cast(b.data()); +} + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +template +inline PointerToPodType buffer_cast(const const_buffer& b) ASIO_NOEXCEPT +{ + return static_cast(b.data()); +} + +/*@}*/ + +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(const mutable_buffer& b, + std::size_t n) ASIO_NOEXCEPT +{ + std::size_t offset = n < b.size() ? n : b.size(); + char* new_data = static_cast(b.data()) + offset; + std::size_t new_size = b.size() - offset; + return mutable_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(std::size_t n, + const mutable_buffer& b) ASIO_NOEXCEPT +{ + return b + n; +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(const const_buffer& b, + std::size_t n) ASIO_NOEXCEPT +{ + std::size_t offset = n < b.size() ? n : b.size(); + const char* new_data = static_cast(b.data()) + offset; + std::size_t new_size = b.size() - offset; + return const_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(std::size_t n, + const const_buffer& b) ASIO_NOEXCEPT +{ + return b + n; +} + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) +namespace detail { + +template +class buffer_debug_check +{ +public: + buffer_debug_check(Iterator iter) + : iter_(iter) + { + } + + ~buffer_debug_check() + { +#if defined(ASIO_MSVC) && (ASIO_MSVC == 1400) + // MSVC 8's string iterator checking may crash in a std::string::iterator + // object's destructor when the iterator points to an already-destroyed + // std::string object, unless the iterator is cleared first. + iter_ = Iterator(); +#endif // defined(ASIO_MSVC) && (ASIO_MSVC == 1400) + } + + void operator()() + { + (void)*iter_; + } + +private: + Iterator iter_; +}; + +} // namespace detail +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + +/** @defgroup buffer asio::buffer + * + * @brief The asio::buffer function is used to create a buffer object to + * represent raw memory, an array of POD elements, a vector of POD elements, + * or a std::string. + * + * A buffer object represents a contiguous region of memory as a 2-tuple + * consisting of a pointer and size in bytes. A tuple of the form {void*, + * size_t} specifies a mutable (modifiable) region of memory. Similarly, a + * tuple of the form {const void*, size_t} specifies a const + * (non-modifiable) region of memory. These two forms correspond to the classes + * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion + * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the + * opposite conversion is not permitted. + * + * The simplest use case involves reading or writing a single buffer of a + * specified size: + * + * @code sock.send(asio::buffer(data, size)); @endcode + * + * In the above example, the return value of asio::buffer meets the + * requirements of the ConstBufferSequence concept so that it may be directly + * passed to the socket's write function. A buffer created for modifiable + * memory also meets the requirements of the MutableBufferSequence concept. + * + * An individual buffer may be created from a builtin array, std::vector, + * std::array or boost::array of POD elements. This helps prevent buffer + * overruns by automatically determining the size of the buffer: + * + * @code char d1[128]; + * size_t bytes_transferred = sock.receive(asio::buffer(d1)); + * + * std::vector d2(128); + * bytes_transferred = sock.receive(asio::buffer(d2)); + * + * std::array d3; + * bytes_transferred = sock.receive(asio::buffer(d3)); + * + * boost::array d4; + * bytes_transferred = sock.receive(asio::buffer(d4)); @endcode + * + * In all three cases above, the buffers created are exactly 128 bytes long. + * Note that a vector is @e never automatically resized when creating or using + * a buffer. The buffer size is determined using the vector's size() + * member function, and not its capacity. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code asio::mutable_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast(b1.data()); + * + * asio::const_buffer b2 = ...; + * std::size_t s2 = b2.size(); + * const void* p2 = b2.data(); @endcode + * + * The @c data() member function permits violations of type safety, so + * uses of it in application code should be carefully considered. + * + * For convenience, a @ref buffer_size function is provided that works with + * both buffers and buffer sequences (that is, types meeting the + * ConstBufferSequence or MutableBufferSequence type requirements). In this + * case, the function returns the total size of all buffers in the sequence. + * + * @par Buffer Copying + * + * The @ref buffer_copy function may be used to copy raw bytes between + * individual buffers and buffer sequences. +* + * In particular, when used with the @ref buffer_size function, the @ref + * buffer_copy function can be used to linearise a sequence of buffers. For + * example: + * + * @code vector buffers = ...; + * + * vector data(asio::buffer_size(buffers)); + * asio::buffer_copy(asio::buffer(data), buffers); @endcode + * + * Note that @ref buffer_copy is implemented in terms of @c memcpy, and + * consequently it cannot be used to copy between overlapping memory regions. + * + * @par Buffer Invalidation + * + * A buffer object does not have any ownership of the memory it refers to. It + * is the responsibility of the application to ensure the memory region remains + * valid until it is no longer required for an I/O operation. When the memory + * is no longer available, the buffer is said to have been invalidated. + * + * For the asio::buffer overloads that accept an argument of type + * std::vector, the buffer objects returned are invalidated by any vector + * operation that also invalidates all references, pointers and iterators + * referring to the elements in the sequence (C++ Std, 23.2.4) + * + * For the asio::buffer overloads that accept an argument of type + * std::basic_string, the buffer objects returned are invalidated according to + * the rules defined for invalidation of references, pointers and iterators + * referring to elements of the sequence (C++ Std, 21.3). + * + * @par Buffer Arithmetic + * + * Buffer objects may be manipulated using simple arithmetic in a safe way + * which helps prevent buffer overruns. Consider an array initialised as + * follows: + * + * @code boost::array a = { 'a', 'b', 'c', 'd', 'e' }; @endcode + * + * A buffer object @c b1 created using: + * + * @code b1 = asio::buffer(a); @endcode + * + * represents the entire array, { 'a', 'b', 'c', 'd', 'e' }. An + * optional second argument to the asio::buffer function may be used to + * limit the size, in bytes, of the buffer: + * + * @code b2 = asio::buffer(a, 3); @endcode + * + * such that @c b2 represents the data { 'a', 'b', 'c' }. Even if the + * size argument exceeds the actual size of the array, the size of the buffer + * object created will be limited to the array size. + * + * An offset may be applied to an existing buffer to create a new one: + * + * @code b3 = b1 + 2; @endcode + * + * where @c b3 will set to represent { 'c', 'd', 'e' }. If the offset + * exceeds the size of the existing buffer, the newly created buffer will be + * empty. + * + * Both an offset and size may be specified to create a buffer that corresponds + * to a specific range of bytes within an existing buffer: + * + * @code b4 = asio::buffer(b1 + 1, 3); @endcode + * + * so that @c b4 will refer to the bytes { 'b', 'c', 'd' }. + * + * @par Buffers and Scatter-Gather I/O + * + * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple + * buffer objects may be assigned into a container that supports the + * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: + * + * @code + * char d1[128]; + * std::vector d2(128); + * boost::array d3; + * + * boost::array bufs1 = { + * asio::buffer(d1), + * asio::buffer(d2), + * asio::buffer(d3) }; + * bytes_transferred = sock.receive(bufs1); + * + * std::vector bufs2; + * bufs2.push_back(asio::buffer(d1)); + * bufs2.push_back(asio::buffer(d2)); + * bufs2.push_back(asio::buffer(d3)); + * bytes_transferred = sock.send(bufs2); @endcode + */ +/*@{*/ + +#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define ASIO_MUTABLE_BUFFER mutable_buffer +# define ASIO_CONST_BUFFER const_buffer +#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define ASIO_MUTABLE_BUFFER mutable_buffers_1 +# define ASIO_CONST_BUFFER const_buffers_1 +#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns mutable_buffer(b). + */ +inline ASIO_MUTABLE_BUFFER buffer( + const mutable_buffer& b) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(b); +} + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode + */ +inline ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER( + mutable_buffer(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns const_buffer(b). + */ +inline ASIO_CONST_BUFFER buffer( + const const_buffer& b) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(b); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode + */ +inline ASIO_CONST_BUFFER buffer(const const_buffer& b, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given memory range. +/** + * @returns mutable_buffer(data, size_in_bytes). + */ +inline ASIO_MUTABLE_BUFFER buffer(void* data, + std::size_t size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data, size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given memory range. +/** + * @returns const_buffer(data, size_in_bytes). + */ +inline ASIO_CONST_BUFFER buffer(const void* data, + std::size_t size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data, size_in_bytes); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N], + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + const PodType (&data)[N]) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data, N * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer(const PodType (&data)[N], + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); +} + +#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +// Borland C++ and Sun Studio think the overloads: +// +// unspecified buffer(boost::array& array ...); +// +// and +// +// unspecified buffer(boost::array& array ...); +// +// are ambiguous. This will be worked around by using a buffer_types traits +// class that contains typedefs for the appropriate buffer and container +// classes, based on whether PodType is const or non-const. + +namespace detail { + +template +struct buffer_types_base; + +template <> +struct buffer_types_base +{ + typedef mutable_buffer buffer_type; + typedef ASIO_MUTABLE_BUFFER container_type; +}; + +template <> +struct buffer_types_base +{ + typedef const_buffer buffer_type; + typedef ASIO_CONST_BUFFER container_type; +}; + +template +struct buffer_types + : public buffer_types_base::value> +{ +}; + +} // namespace detail + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data) ASIO_NOEXCEPT +{ + typedef typename asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), data.size() * sizeof(PodType))); +} + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + typedef typename asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +#else // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer( + boost::array& data) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER( + data.c_array(), data.size() * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer(boost::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + boost::array& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer(boost::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + const boost::array& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer(const boost::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#if defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer( + std::array& data) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_MUTABLE_BUFFER buffer(std::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + std::array& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer(std::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + const std::array& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer(const std::array& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#endif // defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline ASIO_MUTABLE_BUFFER buffer( + std::vector& data) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline ASIO_MUTABLE_BUFFER buffer(std::vector& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline ASIO_CONST_BUFFER buffer( + const std::vector& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline ASIO_CONST_BUFFER buffer( + const std::vector& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given string. +/** + * @returns mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem)). + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline ASIO_MUTABLE_BUFFER buffer( + std::basic_string& data) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given string. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline ASIO_MUTABLE_BUFFER buffer( + std::basic_string& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns const_buffer(data.data(), data.size() * sizeof(Elem)). + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline ASIO_CONST_BUFFER buffer( + const std::basic_string& data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline ASIO_CONST_BUFFER buffer( + const std::basic_string& data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +#if defined(ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given string_view. +/** + * @returns mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem)). + */ +template +inline ASIO_CONST_BUFFER buffer( + basic_string_view data) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + */ +template +inline ASIO_CONST_BUFFER buffer( + basic_string_view data, + std::size_t max_size_in_bytes) ASIO_NOEXCEPT +{ + return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +#endif // defined(ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/// Adapt a basic_string to the DynamicBuffer requirements. +/** + * Requires that sizeof(Elem) == 1. + */ +template +class dynamic_string_buffer +{ +public: + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. + typedef ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. + typedef ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param s The string to be used as backing storage for the dynamic buffer. + * The object stores a reference to the string and the user is responsible + * for ensuring that the string object remains valid while the + * dynamic_string_buffer object, and copies of the object, are in use. + * + * @b DynamicBuffer_v1: Any existing data in the string is treated as the + * dynamic buffer's input sequence. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_string_buffer(std::basic_string& s, + std::size_t maximum_size = + (std::numeric_limits::max)()) ASIO_NOEXCEPT + : string_(s), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits::max)()), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(maximum_size) + { + } + + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_string_buffer(const dynamic_string_buffer& other) ASIO_NOEXCEPT + : string_(other.string_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_string_buffer(dynamic_string_buffer&& other) ASIO_NOEXCEPT + : string_(other.string_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying string if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const ASIO_NOEXCEPT + { +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + return size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(string_.size(), max_size()); + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum size of the underlying memory. + */ + std::size_t max_size() const ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. + /** + * @returns The current capacity of the underlying string if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return (std::min)(string_.capacity(), max_size()); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * the input sequence. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + const_buffers_type data() const ASIO_NOEXCEPT + { + return const_buffers_type(asio::buffer(string_, size_)); + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the basic_string memory. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT + { + return mutable_buffers_type(asio::buffer( + asio::buffer(string_, max_size_) + pos, n)); + } + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const ASIO_NOEXCEPT + { + return const_buffers_type(asio::buffer( + asio::buffer(string_, max_size_) + pos, n)); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + asio::detail::throw_exception(ex); + } + + if (size_ == (std::numeric_limits::max)()) + size_ = string_.size(); // Enable v1 behaviour. + + string_.resize(size_ + n); + + return asio::buffer(asio::buffer(string_) + size_, n); + } + + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, string_.size() - size_); + string_.resize(size_); + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. + /** + * Resizes the string to accommodate an additional @c n bytes at the end. + * + * @throws std::length_error If size() + n > max_size(). + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + asio::detail::throw_exception(ex); + } + + string_.resize(size() + n); + } + + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. + /** + * Erases @c n bytes from the end of the string by resizing the basic_string + * object. If @c n is greater than the current size of the string, the string + * is emptied. + */ + void shrink(std::size_t n) + { + string_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. + * + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string. + * If @c n is greater than the current size of the string, the string is + * emptied. + */ + void consume(std::size_t n) + { +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + string_.erase(0, consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + string_.erase(0, n); + } + +private: + std::basic_string& string_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + std::size_t size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + const std::size_t max_size_; +}; + +/// Adapt a vector to the DynamicBuffer requirements. +/** + * Requires that sizeof(Elem) == 1. + */ +template +class dynamic_vector_buffer +{ +public: + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. + typedef ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. + typedef ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a vector. + /** + * @param v The vector to be used as backing storage for the dynamic buffer. + * The object stores a reference to the vector and the user is responsible + * for ensuring that the vector object remains valid while the + * dynamic_vector_buffer object, and copies of the object, are in use. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_vector_buffer(std::vector& v, + std::size_t maximum_size = + (std::numeric_limits::max)()) ASIO_NOEXCEPT + : vector_(v), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits::max)()), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(maximum_size) + { + } + + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_vector_buffer(const dynamic_vector_buffer& other) ASIO_NOEXCEPT + : vector_(other.vector_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_vector_buffer(dynamic_vector_buffer&& other) ASIO_NOEXCEPT + : vector_(other.vector_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying vector if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const ASIO_NOEXCEPT + { +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + return size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(vector_.size(), max_size()); + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes + * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed + * maximum size of the underlying memory. + */ + std::size_t max_size() const ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. + /** + * @returns @b DynamicBuffer_v1: The current total capacity of the buffer, + * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2: + * The current capacity of the underlying vector if less than max_size(). + * Otherwise returns max_size(). + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return (std::min)(vector_.capacity(), max_size()); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the vector memory in the + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that modifies the input sequence or output + * sequence. + */ + const_buffers_type data() const ASIO_NOEXCEPT + { + return const_buffers_type(asio::buffer(vector_, size_)); + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the vector memory. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT + { + return mutable_buffers_type(asio::buffer( + asio::buffer(vector_, max_size_) + pos, n)); + } + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const ASIO_NOEXCEPT + { + return const_buffers_type(asio::buffer( + asio::buffer(vector_, max_size_) + pos, n)); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * vector object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing vector memory at the + * start of the output sequence of size @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that modifies the input sequence or output + * sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + asio::detail::throw_exception(ex); + } + + if (size_ == (std::numeric_limits::max)()) + size_ = vector_.size(); // Enable v1 behaviour. + + vector_.resize(size_ + n); + + return asio::buffer(asio::buffer(vector_) + size_, n); + } + + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, vector_.size() - size_); + vector_.resize(size_); + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. + /** + * Resizes the vector to accommodate an additional @c n bytes at the end. + * + * @throws std::length_error If size() + n > max_size(). + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + asio::detail::throw_exception(ex); + } + + vector_.resize(size() + n); + } + + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. + /** + * Erases @c n bytes from the end of the vector by resizing the vector + * object. If @c n is greater than the current size of the vector, the vector + * is emptied. + */ + void shrink(std::size_t n) + { + vector_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. + * + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector. + * If @c n is greater than the current size of the vector, the vector is + * emptied. + */ + void consume(std::size_t n) + { +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + vector_.erase(vector_.begin(), vector_.begin() + consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n)); + } + +private: + std::vector& vector_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + std::size_t size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + const std::size_t max_size_; +}; + +/** @defgroup dynamic_buffer asio::dynamic_buffer + * + * @brief The asio::dynamic_buffer function is used to create a + * dynamically resized buffer from a @c std::basic_string or @c std::vector. + */ +/*@{*/ + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns dynamic_string_buffer(data). + */ +template +inline dynamic_string_buffer dynamic_buffer( + std::basic_string& data) ASIO_NOEXCEPT +{ + return dynamic_string_buffer(data); +} + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns dynamic_string_buffer(data, + * max_size). + */ +template +inline dynamic_string_buffer dynamic_buffer( + std::basic_string& data, + std::size_t max_size) ASIO_NOEXCEPT +{ + return dynamic_string_buffer(data, max_size); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns dynamic_vector_buffer(data). + */ +template +inline dynamic_vector_buffer dynamic_buffer( + std::vector& data) ASIO_NOEXCEPT +{ + return dynamic_vector_buffer(data); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns dynamic_vector_buffer(data, max_size). + */ +template +inline dynamic_vector_buffer dynamic_buffer( + std::vector& data, + std::size_t max_size) ASIO_NOEXCEPT +{ + return dynamic_vector_buffer(data, max_size); +} + +/*@}*/ + +/** @defgroup buffer_copy asio::buffer_copy + * + * @brief The asio::buffer_copy function is used to copy bytes from a + * source buffer (or buffer sequence) to a target buffer (or buffer sequence). + * + * The @c buffer_copy function is available in two forms: + * + * @li A 2-argument form: @c buffer_copy(target, source) + * + * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) + * + * Both forms return the number of bytes actually copied. The number of bytes + * copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * @li @c If specified, @c max_bytes_to_copy. + * + * This prevents buffer overflow, regardless of the buffer sizes used in the + * copy operation. + * + * Note that @ref buffer_copy is implemented in terms of @c memcpy, and + * consequently it cannot be used to copy between overlapping memory regions. + */ +/*@{*/ + +namespace detail { + +inline std::size_t buffer_copy_1(const mutable_buffer& target, + const const_buffer& source) +{ + using namespace std; // For memcpy. + std::size_t target_size = target.size(); + std::size_t source_size = source.size(); + std::size_t n = target_size < source_size ? target_size : source_size; + if (n > 0) + memcpy(target.data(), source.data(), n); + return n; +} + +template +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator) ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, *source_begin); +} + +template +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy) ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, + asio::buffer(*source_begin, max_bytes_to_copy)); +} + +template +std::size_t buffer_copy(one_buffer, multiple_buffers, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy + = (std::numeric_limits::max)()) ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + SourceIterator source_iter = source_begin; + + for (mutable_buffer target_buffer( + asio::buffer(*target_begin, max_bytes_to_copy)); + target_buffer.size() && source_iter != source_end; ++source_iter) + { + const_buffer source_buffer(*source_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + target_buffer += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, one_buffer, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy + = (std::numeric_limits::max)()) ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + TargetIterator target_iter = target_begin; + + for (const_buffer source_buffer( + asio::buffer(*source_begin, max_bytes_to_copy)); + source_buffer.size() && target_iter != target_end; ++target_iter) + { + mutable_buffer target_buffer(*target_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + source_buffer += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end) ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + + TargetIterator target_iter = target_begin; + std::size_t target_buffer_offset = 0; + + SourceIterator source_iter = source_begin; + std::size_t source_buffer_offset = 0; + + while (target_iter != target_end && source_iter != source_end) + { + mutable_buffer target_buffer = + mutable_buffer(*target_iter) + target_buffer_offset; + + const_buffer source_buffer = + const_buffer(*source_iter) + source_buffer_offset; + + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + + if (bytes_copied == target_buffer.size()) + { + ++target_iter; + target_buffer_offset = 0; + } + else + target_buffer_offset += bytes_copied; + + if (bytes_copied == source_buffer.size()) + { + ++source_iter; + source_buffer_offset = 0; + } + else + source_buffer_offset += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy) ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + + TargetIterator target_iter = target_begin; + std::size_t target_buffer_offset = 0; + + SourceIterator source_iter = source_begin; + std::size_t source_buffer_offset = 0; + + while (total_bytes_copied != max_bytes_to_copy + && target_iter != target_end && source_iter != source_end) + { + mutable_buffer target_buffer = + mutable_buffer(*target_iter) + target_buffer_offset; + + const_buffer source_buffer = + const_buffer(*source_iter) + source_buffer_offset; + + std::size_t bytes_copied = (buffer_copy_1)( + target_buffer, asio::buffer(source_buffer, + max_bytes_to_copy - total_bytes_copied)); + total_bytes_copied += bytes_copied; + + if (bytes_copied == target_buffer.size()) + { + ++target_iter; + target_buffer_offset = 0; + } + else + target_buffer_offset += bytes_copied; + + if (bytes_copied == source_buffer.size()) + { + ++source_iter; + source_buffer_offset = 0; + } + else + source_buffer_offset += bytes_copied; + } + + return total_bytes_copied; +} + +} // namespace detail + +/// Copies bytes from a source buffer sequence to a target buffer sequence. +/** + * @param target A modifiable buffer sequence representing the memory regions to + * which the bytes will be copied. + * + * @param source A non-modifiable buffer sequence representing the memory + * regions from which the bytes will be copied. + * + * @returns The number of bytes copied. + * + * @note The number of bytes copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * This function is implemented in terms of @c memcpy, and consequently it + * cannot be used to copy between overlapping memory regions. + */ +template +inline std::size_t buffer_copy(const MutableBufferSequence& target, + const ConstBufferSequence& source) ASIO_NOEXCEPT +{ + return detail::buffer_copy( + detail::buffer_sequence_cardinality(), + detail::buffer_sequence_cardinality(), + asio::buffer_sequence_begin(target), + asio::buffer_sequence_end(target), + asio::buffer_sequence_begin(source), + asio::buffer_sequence_end(source)); +} + +/// Copies a limited number of bytes from a source buffer sequence to a target +/// buffer sequence. +/** + * @param target A modifiable buffer sequence representing the memory regions to + * which the bytes will be copied. + * + * @param source A non-modifiable buffer sequence representing the memory + * regions from which the bytes will be copied. + * + * @param max_bytes_to_copy The maximum number of bytes to be copied. + * + * @returns The number of bytes copied. + * + * @note The number of bytes copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * @li @c max_bytes_to_copy + * + * This function is implemented in terms of @c memcpy, and consequently it + * cannot be used to copy between overlapping memory regions. + */ +template +inline std::size_t buffer_copy(const MutableBufferSequence& target, + const ConstBufferSequence& source, + std::size_t max_bytes_to_copy) ASIO_NOEXCEPT +{ + return detail::buffer_copy( + detail::buffer_sequence_cardinality(), + detail::buffer_sequence_cardinality(), + asio::buffer_sequence_begin(target), + asio::buffer_sequence_end(target), + asio::buffer_sequence_begin(source), + asio::buffer_sequence_end(source), max_bytes_to_copy); +} + +/*@}*/ + +} // namespace asio + +#include "asio/detail/pop_options.hpp" +#include "asio/detail/is_buffer_sequence.hpp" +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Trait to determine whether a type satisfies the MutableBufferSequence +/// requirements. +template +struct is_mutable_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_buffer_sequence +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the ConstBufferSequence +/// requirements. +template +struct is_const_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_buffer_sequence +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +/// Trait to determine whether a type satisfies the DynamicBuffer_v1 +/// requirements. +template +struct is_dynamic_buffer_v1 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_dynamic_buffer_v1 +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Trait to determine whether a type satisfies the DynamicBuffer_v2 +/// requirements. +template +struct is_dynamic_buffer_v2 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_dynamic_buffer_v2 +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the DynamicBuffer requirements. +/** + * If @c ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the + * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c + * ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type + * satisfies the DynamicBuffer_v2 requirements. + */ +template +struct is_dynamic_buffer +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#elif defined(ASIO_NO_DYNAMIC_BUFFER_V1) + : asio::is_dynamic_buffer_v2 +#else // defined(ASIO_NO_DYNAMIC_BUFFER_V1) + : asio::is_dynamic_buffer_v1 +#endif // defined(ASIO_NO_DYNAMIC_BUFFER_V1) +{ +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BUFFER_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_read_stream.hpp b/extern/asio-1.18.2/include/asio/buffered_read_stream.hpp new file mode 100644 index 0000000..7ed91dc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_read_stream.hpp @@ -0,0 +1,253 @@ +// +// buffered_read_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_READ_STREAM_HPP +#define ASIO_BUFFERED_READ_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/async_result.hpp" +#include "asio/buffered_read_stream_fwd.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_resize_guard.hpp" +#include "asio/detail/buffered_stream_storage.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Adds buffering to the read-related operations of a stream. +/** + * The buffered_read_stream class template can be used to add buffering to the + * synchronous and asynchronous read operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_read_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_read_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_read_stream(Arg& a, std::size_t buffer_size) + : next_layer_(a), + storage_(buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return next_layer_; + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + next_layer_.close(ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + return next_layer_.write_some(buffers); + } + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return next_layer_.write_some(buffers, ec); + } + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return next_layer_.async_write_some(buffers, + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation. Throws an exception on failure. + std::size_t fill(); + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(asio::error_code& ec); + + /// Start an asynchronous fill. + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_fill( + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers); + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec); + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers); + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec); + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return storage_.size(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(asio::error_code& ec) + { + ec = asio::error_code(); + return storage_.size(); + } + +private: + /// Copy data out of the internal buffer to the specified target buffer. + /// Returns the number of bytes copied. + template + std::size_t copy(const MutableBufferSequence& buffers) + { + std::size_t bytes_copied = asio::buffer_copy( + buffers, storage_.data(), storage_.size()); + storage_.consume(bytes_copied); + return bytes_copied; + } + + /// Copy data from the internal buffer to the specified target buffer, without + /// removing the data from the internal buffer. Returns the number of bytes + /// copied. + template + std::size_t peek_copy(const MutableBufferSequence& buffers) + { + return asio::buffer_copy(buffers, storage_.data(), storage_.size()); + } + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/buffered_read_stream.hpp" + +#endif // ASIO_BUFFERED_READ_STREAM_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_read_stream_fwd.hpp b/extern/asio-1.18.2/include/asio/buffered_read_stream_fwd.hpp new file mode 100644 index 0000000..f189b27 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_read_stream_fwd.hpp @@ -0,0 +1,25 @@ +// +// buffered_read_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_READ_STREAM_FWD_HPP +#define ASIO_BUFFERED_READ_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace asio { + +template +class buffered_read_stream; + +} // namespace asio + +#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_stream.hpp b/extern/asio-1.18.2/include/asio/buffered_stream.hpp new file mode 100644 index 0000000..5d71bf6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_stream.hpp @@ -0,0 +1,279 @@ +// +// buffered_stream.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_STREAM_HPP +#define ASIO_BUFFERED_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/async_result.hpp" +#include "asio/buffered_read_stream.hpp" +#include "asio/buffered_write_stream.hpp" +#include "asio/buffered_stream_fwd.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Adds buffering to the read- and write-related operations of a stream. +/** + * The buffered_stream class template can be used to add buffering to the + * synchronous and asynchronous read and write operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a) + : inner_stream_impl_(a), + stream_impl_(inner_stream_impl_) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a, std::size_t read_buffer_size, + std::size_t write_buffer_size) + : inner_stream_impl_(a, write_buffer_size), + stream_impl_(inner_stream_impl_, read_buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return stream_impl_.next_layer().next_layer(); + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return stream_impl_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return stream_impl_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return stream_impl_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + stream_impl_.close(); + } + + /// Close the stream. + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + stream_impl_.close(ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation. Throws an + /// exception on failure. + std::size_t flush() + { + return stream_impl_.next_layer().flush(); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation, or 0 if an + /// error occurred. + std::size_t flush(asio::error_code& ec) + { + return stream_impl_.next_layer().flush(ec); + } + + /// Start an asynchronous flush. + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_flush( + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return stream_impl_.next_layer().async_flush( + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + return stream_impl_.write_some(buffers); + } + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return stream_impl_.write_some(buffers, ec); + } + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return stream_impl_.async_write_some(buffers, + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation. Throws an exception on failure. + std::size_t fill() + { + return stream_impl_.fill(); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(asio::error_code& ec) + { + return stream_impl_.fill(ec); + } + + /// Start an asynchronous fill. + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_fill( + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + return stream_impl_.read_some(buffers); + } + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return stream_impl_.read_some(buffers, ec); + } + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return stream_impl_.async_read_some(buffers, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers) + { + return stream_impl_.peek(buffers); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return stream_impl_.peek(buffers, ec); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return stream_impl_.in_avail(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(asio::error_code& ec) + { + return stream_impl_.in_avail(ec); + } + +private: + // The buffered write stream. + typedef buffered_write_stream write_stream_type; + write_stream_type inner_stream_impl_; + + // The buffered read stream. + typedef buffered_read_stream read_stream_type; + read_stream_type stream_impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BUFFERED_STREAM_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_stream_fwd.hpp b/extern/asio-1.18.2/include/asio/buffered_stream_fwd.hpp new file mode 100644 index 0000000..d970cbb --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_stream_fwd.hpp @@ -0,0 +1,25 @@ +// +// buffered_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_STREAM_FWD_HPP +#define ASIO_BUFFERED_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace asio { + +template +class buffered_stream; + +} // namespace asio + +#endif // ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_write_stream.hpp b/extern/asio-1.18.2/include/asio/buffered_write_stream.hpp new file mode 100644 index 0000000..526cd60 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_write_stream.hpp @@ -0,0 +1,245 @@ +// +// buffered_write_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_WRITE_STREAM_HPP +#define ASIO_BUFFERED_WRITE_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/buffered_write_stream_fwd.hpp" +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffered_stream_storage.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/write.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Adds buffering to the write-related operations of a stream. +/** + * The buffered_write_stream class template can be used to add buffering to the + * synchronous and asynchronous write operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_write_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_write_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_write_stream(Arg& a, std::size_t buffer_size) + : next_layer_(a), + storage_(buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return next_layer_; + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + next_layer_.close(ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation. Throws an + /// exception on failure. + std::size_t flush(); + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation, or 0 if an + /// error occurred. + std::size_t flush(asio::error_code& ec); + + /// Start an asynchronous flush. + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_flush( + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers); + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred and the error handler did not throw. + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec); + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + return next_layer_.read_some(buffers); + } + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return next_layer_.read_some(buffers, ec); + } + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) + { + return next_layer_.async_read_some(buffers, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers) + { + return next_layer_.peek(buffers); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return next_layer_.peek(buffers, ec); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return next_layer_.in_avail(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(asio::error_code& ec) + { + return next_layer_.in_avail(ec); + } + +private: + /// Copy data into the internal buffer from the specified source buffer. + /// Returns the number of bytes copied. + template + std::size_t copy(const ConstBufferSequence& buffers); + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/buffered_write_stream.hpp" + +#endif // ASIO_BUFFERED_WRITE_STREAM_HPP diff --git a/extern/asio-1.18.2/include/asio/buffered_write_stream_fwd.hpp b/extern/asio-1.18.2/include/asio/buffered_write_stream_fwd.hpp new file mode 100644 index 0000000..8999d9e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffered_write_stream_fwd.hpp @@ -0,0 +1,25 @@ +// +// buffered_write_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERED_WRITE_STREAM_FWD_HPP +#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace asio { + +template +class buffered_write_stream; + +} // namespace asio + +#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/buffers_iterator.hpp b/extern/asio-1.18.2/include/asio/buffers_iterator.hpp new file mode 100644 index 0000000..76b734a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/buffers_iterator.hpp @@ -0,0 +1,521 @@ +// +// buffers_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_BUFFERS_ITERATOR_HPP +#define ASIO_BUFFERS_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/buffer.hpp" +#include "asio/detail/assert.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + template + struct buffers_iterator_types_helper; + + template <> + struct buffers_iterator_types_helper + { + typedef const_buffer buffer_type; + template + struct byte_type + { + typedef typename add_const::type type; + }; + }; + + template <> + struct buffers_iterator_types_helper + { + typedef mutable_buffer buffer_type; + template + struct byte_type + { + typedef ByteType type; + }; + }; + + template + struct buffers_iterator_types + { + enum + { + is_mutable = is_convertible< + typename BufferSequence::value_type, + mutable_buffer>::value + }; + typedef buffers_iterator_types_helper helper; + typedef typename helper::buffer_type buffer_type; + typedef typename helper::template byte_type::type byte_type; + typedef typename BufferSequence::const_iterator const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef const_buffer buffer_type; + typedef typename add_const::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#if !defined(ASIO_NO_DEPRECATED) + + template + struct buffers_iterator_types + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef const_buffer buffer_type; + typedef typename add_const::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#endif // !defined(ASIO_NO_DEPRECATED) +} + +/// A random access iterator over the bytes in a buffer sequence. +template +class buffers_iterator +{ +private: + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::buffer_type buffer_type; + + typedef typename detail::buffers_iterator_types::const_iterator buffer_sequence_iterator_type; + +public: + /// The type used for the distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of the value pointed to by the iterator. + typedef ByteType value_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The type of the result of applying operator->() to the iterator. + /** + * If the buffer sequence stores buffer objects that are convertible to + * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a + * pointer to a const ByteType. + */ + typedef const_or_non_const_ByteType* pointer; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type* pointer; +#endif // defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + /// The type of the result of applying operator*() to the iterator. + /** + * If the buffer sequence stores buffer objects that are convertible to + * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a + * reference to a const ByteType. + */ + typedef const_or_non_const_ByteType& reference; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type& reference; +#endif // defined(GENERATING_DOCUMENTATION) + + /// The iterator category. + typedef std::random_access_iterator_tag iterator_category; + + /// Default constructor. Creates an iterator in an undefined state. + buffers_iterator() + : current_buffer_(), + current_buffer_position_(0), + begin_(), + current_(), + end_(), + position_(0) + { + } + + /// Construct an iterator representing the beginning of the buffers' data. + static buffers_iterator begin(const BufferSequence& buffers) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + __attribute__ ((__noinline__)) +#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + { + buffers_iterator new_iter; + new_iter.begin_ = asio::buffer_sequence_begin(buffers); + new_iter.current_ = asio::buffer_sequence_begin(buffers); + new_iter.end_ = asio::buffer_sequence_end(buffers); + while (new_iter.current_ != new_iter.end_) + { + new_iter.current_buffer_ = *new_iter.current_; + if (new_iter.current_buffer_.size() > 0) + break; + ++new_iter.current_; + } + return new_iter; + } + + /// Construct an iterator representing the end of the buffers' data. + static buffers_iterator end(const BufferSequence& buffers) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + __attribute__ ((__noinline__)) +#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + { + buffers_iterator new_iter; + new_iter.begin_ = asio::buffer_sequence_begin(buffers); + new_iter.current_ = asio::buffer_sequence_begin(buffers); + new_iter.end_ = asio::buffer_sequence_end(buffers); + while (new_iter.current_ != new_iter.end_) + { + buffer_type buffer = *new_iter.current_; + new_iter.position_ += buffer.size(); + ++new_iter.current_; + } + return new_iter; + } + + /// Dereference an iterator. + reference operator*() const + { + return dereference(); + } + + /// Dereference an iterator. + pointer operator->() const + { + return &dereference(); + } + + /// Access an individual element. + reference operator[](std::ptrdiff_t difference) const + { + buffers_iterator tmp(*this); + tmp.advance(difference); + return *tmp; + } + + /// Increment operator (prefix). + buffers_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + buffers_iterator operator++(int) + { + buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Decrement operator (prefix). + buffers_iterator& operator--() + { + decrement(); + return *this; + } + + /// Decrement operator (postfix). + buffers_iterator operator--(int) + { + buffers_iterator tmp(*this); + --*this; + return tmp; + } + + /// Addition operator. + buffers_iterator& operator+=(std::ptrdiff_t difference) + { + advance(difference); + return *this; + } + + /// Subtraction operator. + buffers_iterator& operator-=(std::ptrdiff_t difference) + { + advance(-difference); + return *this; + } + + /// Addition operator. + friend buffers_iterator operator+(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Addition operator. + friend buffers_iterator operator+(std::ptrdiff_t difference, + const buffers_iterator& iter) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Subtraction operator. + friend buffers_iterator operator-(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(-difference); + return tmp; + } + + /// Subtraction operator. + friend std::ptrdiff_t operator-(const buffers_iterator& a, + const buffers_iterator& b) + { + return b.distance_to(a); + } + + /// Test two iterators for equality. + friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) + { + return !a.equal(b); + } + + /// Compare two iterators. + friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) + { + return a.distance_to(b) > 0; + } + + /// Compare two iterators. + friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(b < a); + } + + /// Compare two iterators. + friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) + { + return b < a; + } + + /// Compare two iterators. + friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(a < b); + } + +private: + // Dereference the iterator. + reference dereference() const + { + return static_cast( + current_buffer_.data())[current_buffer_position_]; + } + + // Compare two iterators for equality. + bool equal(const buffers_iterator& other) const + { + return position_ == other.position_; + } + + // Increment the iterator. + void increment() + { + ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); + ++position_; + + // Check if the increment can be satisfied by the current buffer. + ++current_buffer_position_; + if (current_buffer_position_ != current_buffer_.size()) + return; + + // Find the next non-empty buffer. + ++current_; + current_buffer_position_ = 0; + while (current_ != end_) + { + current_buffer_ = *current_; + if (current_buffer_.size() > 0) + return; + ++current_; + } + } + + // Decrement the iterator. + void decrement() + { + ASIO_ASSERT(position_ > 0 && "iterator out of bounds"); + --position_; + + // Check if the decrement can be satisfied by the current buffer. + if (current_buffer_position_ != 0) + { + --current_buffer_position_; + return; + } + + // Find the previous non-empty buffer. + buffer_sequence_iterator_type iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = buffer.size(); + if (buffer_size > 0) + { + current_ = iter; + current_buffer_ = buffer; + current_buffer_position_ = buffer_size - 1; + return; + } + } + } + + // Advance the iterator by the specified distance. + void advance(std::ptrdiff_t n) + { + if (n > 0) + { + ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); + for (;;) + { + std::ptrdiff_t current_buffer_balance + = current_buffer_.size() - current_buffer_position_; + + // Check if the advance can be satisfied by the current buffer. + if (current_buffer_balance > n) + { + position_ += n; + current_buffer_position_ += n; + return; + } + + // Update position. + n -= current_buffer_balance; + position_ += current_buffer_balance; + + // Move to next buffer. If it is empty then it will be skipped on the + // next iteration of this loop. + if (++current_ == end_) + { + ASIO_ASSERT(n == 0 && "iterator out of bounds"); + current_buffer_ = buffer_type(); + current_buffer_position_ = 0; + return; + } + current_buffer_ = *current_; + current_buffer_position_ = 0; + } + } + else if (n < 0) + { + std::size_t abs_n = -n; + ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds"); + for (;;) + { + // Check if the advance can be satisfied by the current buffer. + if (current_buffer_position_ >= abs_n) + { + position_ -= abs_n; + current_buffer_position_ -= abs_n; + return; + } + + // Update position. + abs_n -= current_buffer_position_; + position_ -= current_buffer_position_; + + // Check if we've reached the beginning of the buffers. + if (current_ == begin_) + { + ASIO_ASSERT(abs_n == 0 && "iterator out of bounds"); + current_buffer_position_ = 0; + return; + } + + // Find the previous non-empty buffer. + buffer_sequence_iterator_type iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = buffer.size(); + if (buffer_size > 0) + { + current_ = iter; + current_buffer_ = buffer; + current_buffer_position_ = buffer_size; + break; + } + } + } + } + } + + // Determine the distance between two iterators. + std::ptrdiff_t distance_to(const buffers_iterator& other) const + { + return other.position_ - position_; + } + + buffer_type current_buffer_; + std::size_t current_buffer_position_; + buffer_sequence_iterator_type begin_; + buffer_sequence_iterator_type current_; + buffer_sequence_iterator_type end_; + std::size_t position_; +}; + +/// Construct an iterator representing the beginning of the buffers' data. +template +inline buffers_iterator buffers_begin( + const BufferSequence& buffers) +{ + return buffers_iterator::begin(buffers); +} + +/// Construct an iterator representing the end of the buffers' data. +template +inline buffers_iterator buffers_end( + const BufferSequence& buffers) +{ + return buffers_iterator::end(buffers); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BUFFERS_ITERATOR_HPP diff --git a/extern/asio-1.18.2/include/asio/co_spawn.hpp b/extern/asio-1.18.2/include/asio/co_spawn.hpp new file mode 100644 index 0000000..7d64834 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/co_spawn.hpp @@ -0,0 +1,471 @@ +// +// co_spawn.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_CO_SPAWN_HPP +#define ASIO_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include "asio/awaitable.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct awaitable_signature; + +template +struct awaitable_signature> +{ + typedef void type(std::exception_ptr, T); +}; + +template +struct awaitable_signature> +{ + typedef void type(std::exception_ptr); +}; + +} // namespace detail + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr, T); @endcode + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + */ +template +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(const Executor& ex, awaitable a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint< + (is_executor::value || execution::is_executor::value) + && is_convertible::value + >::type = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * asio::detached); + * @endcode + */ +template +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(const Executor& ex, awaitable a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint< + (is_executor::value || execution::is_executor::value) + && is_convertible::value + >::type = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + */ +template +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(ExecutionContext& ctx, awaitable a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * asio::detached); + * @endcode + */ +template +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(ExecutionContext& ctx, awaitable a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename constraint< + is_convertible::value + && is_convertible::value + >::type = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param f A nullary function object with a return type of the form + * @c asio::awaitable that will be used as the coroutine's entry + * point. + * + * @param token The completion token that will handle the notification that the + * thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * [socket = std::move(my_tcp_socket)]() mutable + * -> asio::awaitable + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, asio::detached); + * @endcode + */ +template ::type>::type) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(const Executor& ex, F&& f, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint< + is_executor::value || execution::is_executor::value + >::type = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param f A nullary function object with a return type of the form + * @c asio::awaitable that will be used as the coroutine's entry + * point. + * + * @param token The completion token that will handle the notification that the + * thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * + * @par Example + * @code + * asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * [socket = std::move(my_tcp_socket)]() mutable + * -> asio::awaitable + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, asio::detached); + * @endcode + */ +template ::type>::type) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename ExecutionContext::executor_type)> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(ExecutionContext& ctx, F&& f, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename constraint< + is_convertible::value + >::type = 0); + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/co_spawn.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_CO_SPAWN_HPP diff --git a/extern/asio-1.18.2/include/asio/completion_condition.hpp b/extern/asio-1.18.2/include/asio/completion_condition.hpp new file mode 100644 index 0000000..cf8c7c2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/completion_condition.hpp @@ -0,0 +1,218 @@ +// +// completion_condition.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_COMPLETION_CONDITION_HPP +#define ASIO_COMPLETION_CONDITION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail { + +// The default maximum number of bytes to transfer in a single operation. +enum default_max_transfer_size_t { default_max_transfer_size = 65536 }; + +// Adapt result of old-style completion conditions (which had a bool result +// where true indicated that the operation was complete). +inline std::size_t adapt_completion_condition_result(bool result) +{ + return result ? 0 : default_max_transfer_size; +} + +// Adapt result of current completion conditions (which have a size_t result +// where 0 means the operation is complete, and otherwise the result is the +// maximum number of bytes to transfer on the next underlying operation). +inline std::size_t adapt_completion_condition_result(std::size_t result) +{ + return result; +} + +class transfer_all_t +{ +public: + typedef std::size_t result_type; + + template + std::size_t operator()(const Error& err, std::size_t) + { + return !!err ? 0 : default_max_transfer_size; + } +}; + +class transfer_at_least_t +{ +public: + typedef std::size_t result_type; + + explicit transfer_at_least_t(std::size_t minimum) + : minimum_(minimum) + { + } + + template + std::size_t operator()(const Error& err, std::size_t bytes_transferred) + { + return (!!err || bytes_transferred >= minimum_) + ? 0 : default_max_transfer_size; + } + +private: + std::size_t minimum_; +}; + +class transfer_exactly_t +{ +public: + typedef std::size_t result_type; + + explicit transfer_exactly_t(std::size_t size) + : size_(size) + { + } + + template + std::size_t operator()(const Error& err, std::size_t bytes_transferred) + { + return (!!err || bytes_transferred >= size_) ? 0 : + (size_ - bytes_transferred < default_max_transfer_size + ? size_ - bytes_transferred : std::size_t(default_max_transfer_size)); + } + +private: + std::size_t size_; +}; + +} // namespace detail + +/** + * @defgroup completion_condition Completion Condition Function Objects + * + * Function objects used for determining when a read or write operation should + * complete. + */ +/*@{*/ + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until all of the data has been transferred, +/// or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full: + * @code + * boost::array buf; + * asio::error_code ec; + * std::size_t n = asio::read( + * sock, asio::buffer(buf), + * asio::transfer_all(), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n == 128 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_all(); +#else +inline detail::transfer_all_t transfer_all() +{ + return detail::transfer_all_t(); +} +#endif + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until a minimum number of bytes has been +/// transferred, or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full or contains at least 64 bytes: + * @code + * boost::array buf; + * asio::error_code ec; + * std::size_t n = asio::read( + * sock, asio::buffer(buf), + * asio::transfer_at_least(64), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n >= 64 && n <= 128 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_at_least(std::size_t minimum); +#else +inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum) +{ + return detail::transfer_at_least_t(minimum); +} +#endif + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until an exact number of bytes has been +/// transferred, or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full or contains exactly 64 bytes: + * @code + * boost::array buf; + * asio::error_code ec; + * std::size_t n = asio::read( + * sock, asio::buffer(buf), + * asio::transfer_exactly(64), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n == 64 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_exactly(std::size_t size); +#else +inline detail::transfer_exactly_t transfer_exactly(std::size_t size) +{ + return detail::transfer_exactly_t(size); +} +#endif + +/*@}*/ + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_COMPLETION_CONDITION_HPP diff --git a/extern/asio-1.18.2/include/asio/compose.hpp b/extern/asio-1.18.2/include/asio/compose.hpp new file mode 100644 index 0000000..3f6f1b8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/compose.hpp @@ -0,0 +1,136 @@ +// +// compose.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_COMPOSE_HPP +#define ASIO_COMPOSE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// Launch an asynchronous operation with a stateful implementation. +/** + * The async_compose function simplifies the implementation of composed + * asynchronous operations automatically wrapping a stateful function object + * with a conforming intermediate completion handler. + * + * @param implementation A function object that contains the implementation of + * the composed asynchronous operation. The first argument to the function + * object is a non-const reference to the enclosing intermediate completion + * handler. The remaining arguments are any arguments that originate from the + * completion handlers of any asynchronous operations performed by the + * implementation. + + * @param token The completion token. + * + * @param io_objects_or_executors Zero or more I/O objects or I/O executors for + * which outstanding work must be maintained. + * + * @par Example: + * + * @code struct async_echo_implementation + * { + * tcp::socket& socket_; + * asio::mutable_buffer buffer_; + * enum { starting, reading, writing } state_; + * + * template + * void operator()(Self& self, + * asio::error_code error = {}, + * std::size_t n = 0) + * { + * switch (state_) + * { + * case starting: + * state_ = reading; + * socket_.async_read_some( + * buffer_, std::move(self)); + * break; + * case reading: + * if (error) + * { + * self.complete(error, 0); + * } + * else + * { + * state_ = writing; + * asio::async_write(socket_, buffer_, + * asio::transfer_exactly(n), + * std::move(self)); + * } + * break; + * case writing: + * self.complete(error, n); + * break; + * } + * } + * }; + * + * template + * auto async_echo(tcp::socket& socket, + * asio::mutable_buffer buffer, + * CompletionToken&& token) -> + * typename asio::async_result< + * typename std::decay::type, + * void(asio::error_code, std::size_t)>::return_type + * { + * return asio::async_compose( + * async_echo_implementation{socket, buffer, + * async_echo_implementation::starting}, + * token, socket); + * } @endcode + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) +async_compose(ASIO_MOVE_ARG(Implementation) implementation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors); + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) +async_compose(ASIO_MOVE_ARG(Implementation) implementation, + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token); + +#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ + template \ + ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \ + async_compose(ASIO_MOVE_ARG(Implementation) implementation, \ + ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + ASIO_VARIADIC_MOVE_PARAMS(n)); + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF) +#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/compose.hpp" + +#endif // ASIO_COMPOSE_HPP diff --git a/extern/asio-1.18.2/include/asio/connect.hpp b/extern/asio-1.18.2/include/asio/connect.hpp new file mode 100644 index 0000000..88cb215 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/connect.hpp @@ -0,0 +1,1076 @@ +// +// connect.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_CONNECT_HPP +#define ASIO_CONNECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/basic_socket.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + char (&has_iterator_helper(...))[2]; + + template + char has_iterator_helper(T*, typename T::iterator* = 0); + + template + struct has_iterator_typedef + { + enum { value = (sizeof((has_iterator_helper)((T*)(0))) == 1) }; + }; +} // namespace detail + +/// Type trait used to determine whether a type is an endpoint sequence that can +/// be used with with @c connect and @c async_connect. +template +struct is_endpoint_sequence +{ +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true if the type may be used as an endpoint sequence. + static const bool value; +#else + enum + { + value = detail::has_iterator_typedef::value + }; +#endif +}; + +/** + * @defgroup connect asio::connect + * + * @brief The @c connect function is a composed operation that establishes a + * socket connection by trying each endpoint in a sequence. + */ +/*@{*/ + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @returns The successfully connected endpoint. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * asio::connect(s, r.resolve(q)); @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, + typename constraint::value>::type = 0); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * asio::error_code ec; + * asio::connect(s, r.resolve(q), ec); + * if (ec) + * { + * // An error occurred. + * } @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, asio::error_code& ec, + typename constraint::value>::type = 0); + +#if !defined(ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, Iterator begin, + typename constraint::value>::type = 0); + +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, + Iterator begin, asio::error_code& ec, + typename constraint::value>::type = 0); +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @returns An iterator denoting the successfully connected endpoint. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * asio::connect(s, e.begin(), e.end()); @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * asio::error_code ec; + * asio::connect(s, e.begin(), e.end(), ec); + * if (ec) + * { + * // An error occurred. + * } @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end, asio::error_code& ec); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns The successfully connected endpoint. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * tcp::endpoint e = asio::connect(s, + * r.resolve(q), my_connect_condition()); + * std::cout << "Connected to: " << e << std::endl; @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename constraint::value>::type = 0); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * asio::error_code ec; + * tcp::endpoint e = asio::connect(s, + * r.resolve(q), my_connect_condition(), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << e << std::endl; + * } @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + asio::error_code& ec, + typename constraint::value>::type = 0); + +#if !defined(ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, + Iterator begin, ConnectCondition connect_condition, + typename constraint::value>::type = 0); + +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, Iterator begin, + ConnectCondition connect_condition, asio::error_code& ec, + typename constraint::value>::type = 0); +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns An iterator denoting the successfully connected endpoint. + * + * @throws asio::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * tcp::resolver::results_type::iterator i = asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); + * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode + */ +template +Iterator connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * asio::error_code ec; + * tcp::resolver::results_type::iterator i = asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << i->endpoint() << std::endl; + * } @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end, ConnectCondition connect_condition, + asio::error_code& ec); + +/*@}*/ + +/** + * @defgroup async_connect asio::async_connect + * + * @brief The @c async_connect function is a composed asynchronous operation + * that establishes a socket connection by trying each endpoint in a sequence. + */ +/*@{*/ + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, the successfully connected endpoint. + * // Otherwise, a default-constructed endpoint. + * const typename Protocol::endpoint& endpoint + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const asio::error_code& ec, + * tcp::resolver::results_type results) + * { + * if (!ec) + * { + * asio::async_connect(s, results, connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const asio::error_code& ec, + * const tcp::endpoint& endpoint) + * { + * // ... + * } @endcode + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, + ASIO_MOVE_ARG(RangeConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint::value>::type = 0); + +#if !defined(ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + ASIO_MOVE_ARG(IteratorConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint::value>::type = 0); +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * @code std::vector endpoints = ...; + * tcp::socket s(my_context); + * asio::async_connect(s, + * endpoints.begin(), endpoints.end(), + * connect_handler); + * + * // ... + * + * void connect_handler( + * const asio::error_code& ec, + * std::vector::iterator i) + * { + * // ... + * } @endcode + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, Iterator end, + ASIO_MOVE_ARG(IteratorConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const asio::error_code& ec, + * tcp::resolver::results_type results) + * { + * if (!ec) + * { + * asio::async_connect(s, results, + * my_connect_condition(), + * connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const asio::error_code& ec, + * const tcp::endpoint& endpoint) + * { + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << endpoint << std::endl; + * } + * } @endcode + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + ASIO_MOVE_ARG(RangeConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint::value>::type = 0); + +#if !defined(ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c asio::ip::tcp::resolver::iterator. + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + ConnectCondition connect_condition, + ASIO_MOVE_ARG(IteratorConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint::value>::type = 0); +#endif // !defined(ASIO_NO_DEPRECATED) + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const asio::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const asio::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const asio::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const asio::error_code& ec, + * tcp::resolver::iterator i) + * { + * if (!ec) + * { + * tcp::resolver::iterator end; + * asio::async_connect(s, i, end, + * my_connect_condition(), + * connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const asio::error_code& ec, + * tcp::resolver::iterator i) + * { + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << i->endpoint() << std::endl; + * } + * } @endcode + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, + ASIO_MOVE_ARG(IteratorConnectHandler) handler + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); + +/*@}*/ + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/connect.hpp" + +#endif diff --git a/extern/asio-1.18.2/include/asio/coroutine.hpp b/extern/asio-1.18.2/include/asio/coroutine.hpp new file mode 100644 index 0000000..bb0bdba --- /dev/null +++ b/extern/asio-1.18.2/include/asio/coroutine.hpp @@ -0,0 +1,328 @@ +// +// coroutine.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_COROUTINE_HPP +#define ASIO_COROUTINE_HPP + +namespace asio { +namespace detail { + +class coroutine_ref; + +} // namespace detail + +/// Provides support for implementing stackless coroutines. +/** + * The @c coroutine class may be used to implement stackless coroutines. The + * class itself is used to store the current state of the coroutine. + * + * Coroutines are copy-constructible and assignable, and the space overhead is + * a single int. They can be used as a base class: + * + * @code class session : coroutine + * { + * ... + * }; @endcode + * + * or as a data member: + * + * @code class session + * { + * ... + * coroutine coro_; + * }; @endcode + * + * or even bound in as a function argument using lambdas or @c bind(). The + * important thing is that as the application maintains a copy of the object + * for as long as the coroutine must be kept alive. + * + * @par Pseudo-keywords + * + * A coroutine is used in conjunction with certain "pseudo-keywords", which + * are implemented as macros. These macros are defined by a header file: + * + * @code #include @endcode + * + * and may conversely be undefined as follows: + * + * @code #include @endcode + * + * reenter + * + * The @c reenter macro is used to define the body of a coroutine. It takes a + * single argument: a pointer or reference to a coroutine object. For example, + * if the base class is a coroutine object you may write: + * + * @code reenter (this) + * { + * ... coroutine body ... + * } @endcode + * + * and if a data member or other variable you can write: + * + * @code reenter (coro_) + * { + * ... coroutine body ... + * } @endcode + * + * When @c reenter is executed at runtime, control jumps to the location of the + * last @c yield or @c fork. + * + * The coroutine body may also be a single statement, such as: + * + * @code reenter (this) for (;;) + * { + * ... + * } @endcode + * + * @b Limitation: The @c reenter macro is implemented using a switch. This + * means that you must take care when using local variables within the + * coroutine body. The local variable is not allowed in a position where + * reentering the coroutine could bypass the variable definition. + * + * yield statement + * + * This form of the @c yield keyword is often used with asynchronous operations: + * + * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode + * + * This divides into four logical steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The statement initiates the asynchronous operation. + * @li The resume point is defined immediately following the statement. + * @li Control is transferred to the end of the coroutine body. + * + * When the asynchronous operation completes, the function object is invoked + * and @c reenter causes control to transfer to the resume point. It is + * important to remember to carry the coroutine state forward with the + * asynchronous operation. In the above snippet, the current class is a + * function object object with a coroutine object as base class or data member. + * + * The statement may also be a compound statement, and this permits us to + * define local variables with limited scope: + * + * @code yield + * { + * mutable_buffers_1 b = buffer(*buffer_); + * socket_->async_read_some(b, *this); + * } @endcode + * + * yield return expression ; + * + * This form of @c yield is often used in generators or coroutine-based parsers. + * For example, the function object: + * + * @code struct interleave : coroutine + * { + * istream& is1; + * istream& is2; + * char operator()(char c) + * { + * reenter (this) for (;;) + * { + * yield return is1.get(); + * yield return is2.get(); + * } + * } + * }; @endcode + * + * defines a trivial coroutine that interleaves the characters from two input + * streams. + * + * This type of @c yield divides into three logical steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The resume point is defined immediately following the semicolon. + * @li The value of the expression is returned from the function. + * + * yield ; + * + * This form of @c yield is equivalent to the following steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The resume point is defined immediately following the semicolon. + * @li Control is transferred to the end of the coroutine body. + * + * This form might be applied when coroutines are used for cooperative + * threading and scheduling is explicitly managed. For example: + * + * @code struct task : coroutine + * { + * ... + * void operator()() + * { + * reenter (this) + * { + * while (... not finished ...) + * { + * ... do something ... + * yield; + * ... do some more ... + * yield; + * } + * } + * } + * ... + * }; + * ... + * task t1, t2; + * for (;;) + * { + * t1(); + * t2(); + * } @endcode + * + * yield break ; + * + * The final form of @c yield is used to explicitly terminate the coroutine. + * This form is comprised of two steps: + * + * @li @c yield sets the coroutine state to indicate termination. + * @li Control is transferred to the end of the coroutine body. + * + * Once terminated, calls to is_complete() return true and the coroutine cannot + * be reentered. + * + * Note that a coroutine may also be implicitly terminated if the coroutine + * body is exited without a yield, e.g. by return, throw or by running to the + * end of the body. + * + * fork statement + * + * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting + * it into two (or more) copies. One use of @c fork is in a server, where a new + * coroutine is created to handle each client connection: + * + * @code reenter (this) + * { + * do + * { + * socket_.reset(new tcp::socket(my_context_)); + * yield acceptor->async_accept(*socket_, *this); + * fork server(*this)(); + * } while (is_parent()); + * ... client-specific handling follows ... + * } @endcode + * + * The logical steps involved in a @c fork are: + * + * @li @c fork saves the current state of the coroutine. + * @li The statement creates a copy of the coroutine and either executes it + * immediately or schedules it for later execution. + * @li The resume point is defined immediately following the semicolon. + * @li For the "parent", control immediately continues from the next line. + * + * The functions is_parent() and is_child() can be used to differentiate + * between parent and child. You would use these functions to alter subsequent + * control flow. + * + * Note that @c fork doesn't do the actual forking by itself. It is the + * application's responsibility to create a clone of the coroutine and call it. + * The clone can be called immediately, as above, or scheduled for delayed + * execution using something like asio::post(). + * + * @par Alternate macro names + * + * If preferred, an application can use macro names that follow a more typical + * naming convention, rather than the pseudo-keywords. These are: + * + * @li @c ASIO_CORO_REENTER instead of @c reenter + * @li @c ASIO_CORO_YIELD instead of @c yield + * @li @c ASIO_CORO_FORK instead of @c fork + */ +class coroutine +{ +public: + /// Constructs a coroutine in its initial state. + coroutine() : value_(0) {} + + /// Returns true if the coroutine is the child of a fork. + bool is_child() const { return value_ < 0; } + + /// Returns true if the coroutine is the parent of a fork. + bool is_parent() const { return !is_child(); } + + /// Returns true if the coroutine has reached its terminal state. + bool is_complete() const { return value_ == -1; } + +private: + friend class detail::coroutine_ref; + int value_; +}; + + +namespace detail { + +class coroutine_ref +{ +public: + coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} + coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} + ~coroutine_ref() { if (!modified_) value_ = -1; } + operator int() const { return value_; } + int& operator=(int v) { modified_ = true; return value_ = v; } +private: + void operator=(const coroutine_ref&); + int& value_; + bool modified_; +}; + +} // namespace detail +} // namespace asio + +#define ASIO_CORO_REENTER(c) \ + switch (::asio::detail::coroutine_ref _coro_value = c) \ + case -1: if (_coro_value) \ + { \ + goto terminate_coroutine; \ + terminate_coroutine: \ + _coro_value = -1; \ + goto bail_out_of_coroutine; \ + bail_out_of_coroutine: \ + break; \ + } \ + else /* fall-through */ case 0: + +#define ASIO_CORO_YIELD_IMPL(n) \ + for (_coro_value = (n);;) \ + if (_coro_value == 0) \ + { \ + case (n): ; \ + break; \ + } \ + else \ + switch (_coro_value ? 0 : 1) \ + for (;;) \ + /* fall-through */ case -1: if (_coro_value) \ + goto terminate_coroutine; \ + else for (;;) \ + /* fall-through */ case 1: if (_coro_value) \ + goto bail_out_of_coroutine; \ + else /* fall-through */ case 0: + +#define ASIO_CORO_FORK_IMPL(n) \ + for (_coro_value = -(n);; _coro_value = (n)) \ + if (_coro_value == (n)) \ + { \ + case -(n): ; \ + break; \ + } \ + else + +#if defined(_MSC_VER) +# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1) +# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__COUNTER__ + 1) +#else // defined(_MSC_VER) +# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__LINE__) +# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__LINE__) +#endif // defined(_MSC_VER) + +#endif // ASIO_COROUTINE_HPP diff --git a/extern/asio-1.18.2/include/asio/deadline_timer.hpp b/extern/asio-1.18.2/include/asio/deadline_timer.hpp new file mode 100644 index 0000000..73872c8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/deadline_timer.hpp @@ -0,0 +1,38 @@ +// +// deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DEADLINE_TIMER_HPP +#define ASIO_DEADLINE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/socket_types.hpp" // Must come before posix_time. +#include "asio/basic_deadline_timer.hpp" + +#include + +namespace asio { + +/// Typedef for the typical usage of timer. Uses a UTC clock. +typedef basic_deadline_timer deadline_timer; + +} // namespace asio + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_DEADLINE_TIMER_HPP diff --git a/extern/asio-1.18.2/include/asio/defer.hpp b/extern/asio-1.18.2/include/asio/defer.hpp new file mode 100644 index 0000000..b0829e8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/defer.hpp @@ -0,0 +1,130 @@ +// +// defer.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DEFER_HPP +#define ASIO_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution_context.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from defer(). + * + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex by performing + * get_associated_executor(handler). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Performs ex.defer(std::move(handler), alloc). + * + * @li Returns result.get(). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( + ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from defer(). + * + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * get_associated_executor(handler). + * + * @li Creates a work object @c w by performing make_work(ex1). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Constructs a function object @c f with a function call operator that + * performs ex1.dispatch(std::move(handler), alloc) followed by + * w.reset(). + * + * @li Performs Executor(ex).defer(std::move(f), alloc). + * + * @li Returns result.get(). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, + ASIO_MOVE_ARG(CompletionToken) token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint< + execution::is_executor::value || is_executor::value + >::type = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns defer(ctx.get_executor(), forward(token)). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, + ASIO_MOVE_ARG(CompletionToken) token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename constraint::value>::type = 0); + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/defer.hpp" + +#endif // ASIO_DEFER_HPP diff --git a/extern/asio-1.18.2/include/asio/detached.hpp b/extern/asio-1.18.2/include/asio/detached.hpp new file mode 100644 index 0000000..e99875e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detached.hpp @@ -0,0 +1,112 @@ +// +// detached.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETACHED_HPP +#define ASIO_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Class used to specify that an asynchronous operation is detached. +/** + + * The detached_t class is used to indicate that an asynchronous operation is + * detached. That is, there is no completion handler waiting for the + * operation's result. A detached_t object may be passed as a handler to an + * asynchronous operation, typically using the special value + * @c asio::detached. For example: + + * @code my_socket.async_send(my_buffer, asio::detached); + * @endcode + */ +class detached_t +{ +public: + /// Constructor. + ASIO_CONSTEXPR detached_t() + { + } + + /// Adapts an executor to add the @c detached_t completion token as the + /// default. + template + struct executor_with_default : InnerExecutor + { + /// Specify @c detached_t as the default completion token type. + typedef detached_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template + executor_with_default(const OtherExecutor& ex, + typename constraint< + is_convertible::value + >::type = 0) ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c detached_t as its + /// default completion token type. +#if defined(ASIO_HAS_ALIAS_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + template + using as_default_on_t = typename T::template rebind_executor< + executor_with_default >::other; +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + /// Function helper to adapt an I/O object to use @c detached_t as its + /// default completion token type. + template + static typename decay::type::template rebind_executor< + executor_with_default::type::executor_type> + >::other + as_default_on(ASIO_MOVE_ARG(T) object) + { + return typename decay::type::template rebind_executor< + executor_with_default::type::executor_type> + >::other(ASIO_MOVE_CAST(T)(object)); + } +}; + +/// A special value, similar to std::nothrow. +/** + * See the documentation for asio::detached_t for a usage example. + */ +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr detached_t detached; +#elif defined(ASIO_MSVC) +__declspec(selectany) detached_t detached; +#endif + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/detached.hpp" + +#endif // ASIO_DETACHED_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/array.hpp b/extern/asio-1.18.2/include/asio/detail/array.hpp new file mode 100644 index 0000000..ef230c3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/array.hpp @@ -0,0 +1,38 @@ +// +// detail/array.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_ARRAY_HPP +#define ASIO_DETAIL_ARRAY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_ARRAY) +# include +#else // defined(ASIO_HAS_STD_ARRAY) +# include +#endif // defined(ASIO_HAS_STD_ARRAY) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_ARRAY) +using std::array; +#else // defined(ASIO_HAS_STD_ARRAY) +using boost::array; +#endif // defined(ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_ARRAY_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/array_fwd.hpp b/extern/asio-1.18.2/include/asio/detail/array_fwd.hpp new file mode 100644 index 0000000..fb81dba --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/array_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_ARRAY_FWD_HPP +#define ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace boost { + +template +class array; + +} // namespace boost + +// Standard library components can't be forward declared, so we'll have to +// include the array header. Fortunately, it's fairly lightweight and doesn't +// add significantly to the compile time. +#if defined(ASIO_HAS_STD_ARRAY) +# include +#endif // defined(ASIO_HAS_STD_ARRAY) + +#endif // ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/assert.hpp b/extern/asio-1.18.2/include/asio/detail/assert.hpp new file mode 100644 index 0000000..8eaf595 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/assert.hpp @@ -0,0 +1,32 @@ +// +// detail/assert.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_ASSERT_HPP +#define ASIO_DETAIL_ASSERT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_ASSERT) +# include +#else // defined(ASIO_HAS_BOOST_ASSERT) +# include +#endif // defined(ASIO_HAS_BOOST_ASSERT) + +#if defined(ASIO_HAS_BOOST_ASSERT) +# define ASIO_ASSERT(expr) BOOST_ASSERT(expr) +#else // defined(ASIO_HAS_BOOST_ASSERT) +# define ASIO_ASSERT(expr) assert(expr) +#endif // defined(ASIO_HAS_BOOST_ASSERT) + +#endif // ASIO_DETAIL_ASSERT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/atomic_count.hpp b/extern/asio-1.18.2/include/asio/detail/atomic_count.hpp new file mode 100644 index 0000000..8409298 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/atomic_count.hpp @@ -0,0 +1,64 @@ +// +// detail/atomic_count.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_ATOMIC_COUNT_HPP +#define ASIO_DETAIL_ATOMIC_COUNT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +// Nothing to include. +#elif defined(ASIO_HAS_STD_ATOMIC) +# include +#else // defined(ASIO_HAS_STD_ATOMIC) +# include +#endif // defined(ASIO_HAS_STD_ATOMIC) + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef long atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } +inline void ref_count_up(atomic_count& a) { ++a; } +inline bool ref_count_down(atomic_count& a) { return --a == 0; } +#elif defined(ASIO_HAS_STD_ATOMIC) +typedef std::atomic atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } + +inline void ref_count_up(atomic_count& a) +{ + a.fetch_add(1, std::memory_order_relaxed); +} + +inline bool ref_count_down(atomic_count& a) +{ + if (a.fetch_sub(1, std::memory_order_release) == 1) + { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + return false; +} +#else // defined(ASIO_HAS_STD_ATOMIC) +typedef boost::detail::atomic_count atomic_count; +inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } +inline void ref_count_up(atomic_count& a) { ++a; } +inline bool ref_count_down(atomic_count& a) { return --a == 0; } +#endif // defined(ASIO_HAS_STD_ATOMIC) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_ATOMIC_COUNT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/base_from_completion_cond.hpp b/extern/asio-1.18.2/include/asio/detail/base_from_completion_cond.hpp new file mode 100644 index 0000000..0139d26 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/base_from_completion_cond.hpp @@ -0,0 +1,69 @@ +// +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP +#define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/completion_condition.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(CompletionCondition& completion_condition) + : completion_condition_( + ASIO_MOVE_CAST(CompletionCondition)(completion_condition)) + { + } + + std::size_t check_for_completion( + const asio::error_code& ec, + std::size_t total_transferred) + { + return detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred)); + } + +private: + CompletionCondition completion_condition_; +}; + +template <> +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(transfer_all_t) + { + } + + static std::size_t check_for_completion( + const asio::error_code& ec, + std::size_t total_transferred) + { + return transfer_all_t()(ec, total_transferred); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/bind_handler.hpp b/extern/asio-1.18.2/include/asio/detail/bind_handler.hpp new file mode 100644 index 0000000..7151050 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/bind_handler.hpp @@ -0,0 +1,938 @@ +// +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BIND_HANDLER_HPP +#define ASIO_DETAIL_BIND_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class binder1 +{ +public: + template + binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1) + { + } + + binder1(Handler& handler, const Arg1& arg1) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1) + { + } + +#if defined(ASIO_HAS_MOVE) + binder1(const binder1& other) + : handler_(other.handler_), + arg1_(other.arg1_) + { + } + + binder1(binder1&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_)); + } + + void operator()() const + { + handler_(arg1_); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + binder1* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + binder1* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + binder1* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + binder1* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + binder1* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline binder1::type, Arg1> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) +{ + return binder1::type, Arg1>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1); +} + +template +class binder2 +{ +public: + template + binder2(int, ASIO_MOVE_ARG(T) handler, + const Arg1& arg1, const Arg2& arg2) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + + binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + +#if defined(ASIO_HAS_MOVE) + binder2(const binder2& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_) + { + } + + binder2(binder2&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_)); + } + + void operator()() const + { + handler_(arg1_, arg2_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + binder2* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + binder2* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + binder2* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + binder2* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + binder2* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline binder2::type, Arg1, Arg2> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) +{ + return binder2::type, Arg1, Arg2>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); +} + +template +class binder3 +{ +public: + template + binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + binder3(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + +#if defined(ASIO_HAS_MOVE) + binder3(const binder3& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_) + { + } + + binder3(binder3&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + binder3* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + binder3* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + binder3* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + binder3* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + binder3* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline binder3::type, Arg1, Arg2, Arg3> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) +{ + return binder3::type, Arg1, Arg2, Arg3>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); +} + +template +class binder4 +{ +public: + template + binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + + binder4(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + +#if defined(ASIO_HAS_MOVE) + binder4(const binder4& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_) + { + } + + binder4(binder4&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_), + static_cast(arg4_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + binder4* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + binder4* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + binder4* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + binder4* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + binder4* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline binder4::type, Arg1, Arg2, Arg3, Arg4> +bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) +{ + return binder4::type, Arg1, Arg2, Arg3, Arg4>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); +} + +template +class binder5 +{ +public: + template + binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + + binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + +#if defined(ASIO_HAS_MOVE) + binder5(const binder5& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_), + arg5_(other.arg5_) + { + } + + binder5(binder5&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)), + arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_), + static_cast(arg4_), static_cast(arg5_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; + Arg5 arg5_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + binder5* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + binder5* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + binder5* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + binder5* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + binder5* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline binder5::type, Arg1, Arg2, Arg3, Arg4, Arg5> +bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +{ + return binder5::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5); +} + +#if defined(ASIO_HAS_MOVE) + +template +class move_binder1 +{ +public: + move_binder1(int, ASIO_MOVE_ARG(Handler) handler, + ASIO_MOVE_ARG(Arg1) arg1) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(ASIO_MOVE_CAST(Arg1)(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } + + void operator()() + { + handler_(ASIO_MOVE_CAST(Arg1)(arg1_)); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + move_binder1* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + move_binder1* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + move_binder1* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder1* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +class move_binder2 +{ +public: + move_binder2(int, ASIO_MOVE_ARG(Handler) handler, + const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(ASIO_MOVE_CAST(Arg2)(arg2)) + { + } + + move_binder2(move_binder2&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } + + void operator()() + { + handler_(static_cast(arg1_), + ASIO_MOVE_CAST(Arg2)(arg2_)); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + move_binder2* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + move_binder2* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + move_binder2* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder2* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::binder1& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::binder2& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor, Executor> + : detail::associated_executor_forwarding_base +{ + typedef typename associated_executor::type type; + + static type get(const detail::binder1& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_executor, Executor> + : detail::associated_executor_forwarding_base +{ + typedef typename associated_executor::type type; + + static type get(const detail::binder2& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#if defined(ASIO_HAS_MOVE) + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::move_binder1& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_allocator< + detail::move_binder2, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::move_binder2& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor, Executor> + : detail::associated_executor_forwarding_base +{ + typedef typename associated_executor::type type; + + static type get(const detail::move_binder1& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_executor, Executor> + : detail::associated_executor_forwarding_base +{ + typedef typename associated_executor::type type; + + static type get(const detail::move_binder2& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BIND_HANDLER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/blocking_executor_op.hpp b/extern/asio-1.18.2/include/asio/detail/blocking_executor_op.hpp new file mode 100644 index 0000000..d58df20 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/blocking_executor_op.hpp @@ -0,0 +1,107 @@ +// +// detail/blocking_executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP +#define ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/scheduler_operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class blocking_executor_op_base : public Operation +{ +public: + blocking_executor_op_base(typename Operation::func_type complete_func) + : Operation(complete_func), + is_complete_(false) + { + } + + void wait() + { + asio::detail::mutex::scoped_lock lock(mutex_); + while (!is_complete_) + event_.wait(lock); + } + +protected: + struct do_complete_cleanup + { + ~do_complete_cleanup() + { + asio::detail::mutex::scoped_lock lock(op_->mutex_); + op_->is_complete_ = true; + op_->event_.unlock_and_signal_one_for_destruction(lock); + } + + blocking_executor_op_base* op_; + }; + +private: + asio::detail::mutex mutex_; + asio::detail::event event_; + bool is_complete_; +}; + +template +class blocking_executor_op : public blocking_executor_op_base +{ +public: + blocking_executor_op(Handler& h) + : blocking_executor_op_base(&blocking_executor_op::do_complete), + handler_(h) + { + } + + static void do_complete(void* owner, Operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + blocking_executor_op* o(static_cast(base)); + + typename blocking_executor_op_base::do_complete_cleanup + on_exit = { o }; + (void)on_exit; + + ASIO_HANDLER_COMPLETION((*o)); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + asio_handler_invoke_helpers::invoke(o->handler_, o->handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler& handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/buffer_resize_guard.hpp b/extern/asio-1.18.2/include/asio/detail/buffer_resize_guard.hpp new file mode 100644 index 0000000..00f4aa3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/buffer_resize_guard.hpp @@ -0,0 +1,66 @@ +// +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP +#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/limits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to manage buffer resizing in an exception safe way. +template +class buffer_resize_guard +{ +public: + // Constructor. + buffer_resize_guard(Buffer& buffer) + : buffer_(buffer), + old_size_(buffer.size()) + { + } + + // Destructor rolls back the buffer resize unless commit was called. + ~buffer_resize_guard() + { + if (old_size_ != (std::numeric_limits::max)()) + { + buffer_.resize(old_size_); + } + } + + // Commit the resize transaction. + void commit() + { + old_size_ = (std::numeric_limits::max)(); + } + +private: + // The buffer being managed. + Buffer& buffer_; + + // The size of the buffer at the time the guard was constructed. + size_t old_size_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/buffer_sequence_adapter.hpp b/extern/asio-1.18.2/include/asio/detail/buffer_sequence_adapter.hpp new file mode 100644 index 0000000..89b05ce --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/buffer_sequence_adapter.hpp @@ -0,0 +1,650 @@ +// +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP +#define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffer_sequence_adapter_base +{ +#if defined(ASIO_WINDOWS_RUNTIME) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 1 }; + +protected: + typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; + + ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const asio::mutable_buffer& buffer); + + ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const asio::const_buffer& buffer); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef WSABUF native_buffer_type; + + static void init_native_buffer(WSABUF& buf, + const asio::mutable_buffer& buffer) + { + buf.buf = static_cast(buffer.data()); + buf.len = static_cast(buffer.size()); + } + + static void init_native_buffer(WSABUF& buf, + const asio::const_buffer& buffer) + { + buf.buf = const_cast(static_cast(buffer.data())); + buf.len = static_cast(buffer.size()); + } +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef iovec native_buffer_type; + + static void init_iov_base(void*& base, void* addr) + { + base = addr; + } + + template + static void init_iov_base(T& base, void* addr) + { + base = static_cast(addr); + } + + static void init_native_buffer(iovec& iov, + const asio::mutable_buffer& buffer) + { + init_iov_base(iov.iov_base, buffer.data()); + iov.iov_len = buffer.size(); + } + + static void init_native_buffer(iovec& iov, + const asio::const_buffer& buffer) + { + init_iov_base(iov.iov_base, const_cast(buffer.data())); + iov.iov_len = buffer.size(); + } +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +}; + +// Helper class to translate buffers into the native buffer representation. +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = false }; + + explicit buffer_sequence_adapter(const Buffers& buffer_sequence) + : count_(0), total_buffer_size_(0) + { + buffer_sequence_adapter::init( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return count_; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::all_empty( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + static void validate(const Buffers& buffer_sequence) + { + buffer_sequence_adapter::validate( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + static Buffer first(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::first( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const Buffers& buffer_sequence, + const asio::mutable_buffer& storage) + { + return buffer_sequence_adapter::linearise( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence), storage); + } + +private: + template + void init(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end && count_ < max_buffers; ++iter, ++count_) + { + Buffer buffer(*iter); + init_native_buffer(buffers_[count_], buffer); + total_buffer_size_ += buffer.size(); + } + } + + template + static bool all_empty(Iterator begin, Iterator end) + { + Iterator iter = begin; + std::size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + if (Buffer(*iter).size() > 0) + return false; + return true; + } + + template + static void validate(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + buffer.data(); + } + } + + template + static Buffer first(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + if (buffer.size() != 0) + return buffer; + } + return Buffer(); + } + + template + static Buffer linearise(Iterator begin, Iterator end, + const asio::mutable_buffer& storage) + { + asio::mutable_buffer unused_storage = storage; + Iterator iter = begin; + while (iter != end && unused_storage.size() != 0) + { + Buffer buffer(*iter); + ++iter; + if (buffer.size() == 0) + continue; + if (unused_storage.size() == storage.size()) + { + if (iter == end) + return buffer; + if (buffer.size() >= unused_storage.size()) + return buffer; + } + unused_storage += asio::buffer_copy(unused_storage, buffer); + } + return Buffer(storage.data(), storage.size() - unused_storage.size()); + } + + native_buffer_type buffers_[max_buffers]; + std::size_t count_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::mutable_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::mutable_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::mutable_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::mutable_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::mutable_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::const_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::const_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::const_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::const_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::const_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::mutable_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::mutable_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::mutable_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::mutable_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::mutable_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::const_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::const_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::const_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::const_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::const_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template +class buffer_sequence_adapter > + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = false }; + + explicit buffer_sequence_adapter( + const boost::array& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::array& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const boost::array& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const boost::array& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const boost::array& buffer_sequence, + const asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + asio::buffer_copy(storage, buffer_sequence)); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template +class buffer_sequence_adapter > + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = false }; + + explicit buffer_sequence_adapter( + const std::array& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const std::array& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const std::array& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const std::array& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const std::array& buffer_sequence, + const asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + asio::buffer_copy(storage, buffer_sequence)); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/buffer_sequence_adapter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/buffered_stream_storage.hpp b/extern/asio-1.18.2/include/asio/detail/buffered_stream_storage.hpp new file mode 100644 index 0000000..04cef82 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/buffered_stream_storage.hpp @@ -0,0 +1,126 @@ +// +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP +#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/assert.hpp" +#include +#include +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffered_stream_storage +{ +public: + // The type of the bytes stored in the buffer. + typedef unsigned char byte_type; + + // The type used for offsets into the buffer. + typedef std::size_t size_type; + + // Constructor. + explicit buffered_stream_storage(std::size_t buffer_capacity) + : begin_offset_(0), + end_offset_(0), + buffer_(buffer_capacity) + { + } + + /// Clear the buffer. + void clear() + { + begin_offset_ = 0; + end_offset_ = 0; + } + + // Return a pointer to the beginning of the unread data. + mutable_buffer data() + { + return asio::buffer(buffer_) + begin_offset_; + } + + // Return a pointer to the beginning of the unread data. + const_buffer data() const + { + return asio::buffer(buffer_) + begin_offset_; + } + + // Is there no unread data in the buffer. + bool empty() const + { + return begin_offset_ == end_offset_; + } + + // Return the amount of unread data the is in the buffer. + size_type size() const + { + return end_offset_ - begin_offset_; + } + + // Resize the buffer to the specified length. + void resize(size_type length) + { + ASIO_ASSERT(length <= capacity()); + if (begin_offset_ + length <= capacity()) + { + end_offset_ = begin_offset_ + length; + } + else + { + using namespace std; // For memmove. + memmove(&buffer_[0], &buffer_[0] + begin_offset_, size()); + end_offset_ = length; + begin_offset_ = 0; + } + } + + // Return the maximum size for data in the buffer. + size_type capacity() const + { + return buffer_.size(); + } + + // Consume multiple bytes from the beginning of the buffer. + void consume(size_type count) + { + ASIO_ASSERT(begin_offset_ + count <= end_offset_); + begin_offset_ += count; + if (empty()) + clear(); + } + +private: + // The offset to the beginning of the unread data. + size_type begin_offset_; + + // The offset to the end of the unread data. + size_type end_offset_; + + // The data in the buffer. + std::vector buffer_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/bulk_executor_op.hpp b/extern/asio-1.18.2/include/asio/detail/bulk_executor_op.hpp new file mode 100644 index 0000000..8f6921b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/bulk_executor_op.hpp @@ -0,0 +1,88 @@ +// +// detail/bulk_executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_BULK_EXECUTOR_OP_HPP +#define ASIO_DETAIL_BULK_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/scheduler_operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class bulk_executor_op : public Operation +{ +public: + ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(bulk_executor_op); + + template + bulk_executor_op(ASIO_MOVE_ARG(H) h, + const Alloc& allocator, std::size_t i) + : Operation(&bulk_executor_op::do_complete), + handler_(ASIO_MOVE_CAST(H)(h)), + allocator_(allocator), + index_(i) + { + } + + static void do_complete(void* owner, Operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + bulk_executor_op* o(static_cast(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 handler(o->handler_, o->index_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + Alloc allocator_; + std::size_t index_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BULK_EXECUTOR_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/call_stack.hpp b/extern/asio-1.18.2/include/asio/detail/call_stack.hpp new file mode 100644 index 0000000..40f762d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/call_stack.hpp @@ -0,0 +1,125 @@ +// +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CALL_STACK_HPP +#define ASIO_DETAIL_CALL_STACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/tss_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to determine whether or not the current thread is inside an +// invocation of io_context::run() for a specified io_context object. +template +class call_stack +{ +public: + // Context class automatically pushes the key/value pair on to the stack. + class context + : private noncopyable + { + public: + // Push the key on to the stack. + explicit context(Key* k) + : key_(k), + next_(call_stack::top_) + { + value_ = reinterpret_cast(this); + call_stack::top_ = this; + } + + // Push the key/value pair on to the stack. + context(Key* k, Value& v) + : key_(k), + value_(&v), + next_(call_stack::top_) + { + call_stack::top_ = this; + } + + // Pop the key/value pair from the stack. + ~context() + { + call_stack::top_ = next_; + } + + // Find the next context with the same key. + Value* next_by_key() const + { + context* elem = next_; + while (elem) + { + if (elem->key_ == key_) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + private: + friend class call_stack; + + // The key associated with the context. + Key* key_; + + // The value associated with the context. + Value* value_; + + // The next element in the stack. + context* next_; + }; + + friend class context; + + // Determine whether the specified owner is on the stack. Returns address of + // key if present, 0 otherwise. + static Value* contains(Key* k) + { + context* elem = top_; + while (elem) + { + if (elem->key_ == k) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + // Obtain the value at the top of the stack. + static Value* top() + { + context* elem = top_; + return elem ? elem->value_ : 0; + } + +private: + // The top of the stack of calls for the current thread. + static tss_ptr top_; +}; + +template +tss_ptr::context> +call_stack::top_; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CALL_STACK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/chrono.hpp b/extern/asio-1.18.2/include/asio/detail/chrono.hpp new file mode 100644 index 0000000..0abae1c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/chrono.hpp @@ -0,0 +1,66 @@ +// +// detail/chrono.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CHRONO_HPP +#define ASIO_DETAIL_CHRONO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_CHRONO) +# include +#elif defined(ASIO_HAS_BOOST_CHRONO) +# include +#endif // defined(ASIO_HAS_BOOST_CHRONO) + +namespace asio { +namespace chrono { + +#if defined(ASIO_HAS_STD_CHRONO) +using std::chrono::duration; +using std::chrono::time_point; +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::microseconds; +using std::chrono::milliseconds; +using std::chrono::seconds; +using std::chrono::minutes; +using std::chrono::hours; +using std::chrono::time_point_cast; +#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +typedef std::chrono::monotonic_clock steady_clock; +#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::steady_clock; +#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::system_clock; +using std::chrono::high_resolution_clock; +#elif defined(ASIO_HAS_BOOST_CHRONO) +using boost::chrono::duration; +using boost::chrono::time_point; +using boost::chrono::duration_cast; +using boost::chrono::nanoseconds; +using boost::chrono::microseconds; +using boost::chrono::milliseconds; +using boost::chrono::seconds; +using boost::chrono::minutes; +using boost::chrono::hours; +using boost::chrono::time_point_cast; +using boost::chrono::system_clock; +using boost::chrono::steady_clock; +using boost::chrono::high_resolution_clock; +#endif // defined(ASIO_HAS_BOOST_CHRONO) + +} // namespace chrono +} // namespace asio + +#endif // ASIO_DETAIL_CHRONO_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/chrono_time_traits.hpp b/extern/asio-1.18.2/include/asio/detail/chrono_time_traits.hpp new file mode 100644 index 0000000..17b9645 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/chrono_time_traits.hpp @@ -0,0 +1,190 @@ +// +// detail/chrono_time_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP +#define ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/cstdint.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper template to compute the greatest common divisor. +template +struct gcd { enum { value = gcd::value }; }; + +template +struct gcd { enum { value = v1 }; }; + +// Adapts std::chrono clocks for use with a deadline timer. +template +struct chrono_time_traits +{ + // The clock type. + typedef Clock clock_type; + + // The duration type of the clock. + typedef typename clock_type::duration duration_type; + + // The time point type of the clock. + typedef typename clock_type::time_point time_type; + + // The period of the clock. + typedef typename duration_type::period period_type; + + // Get the current time. + static time_type now() + { + return clock_type::now(); + } + + // Add a duration to a time. + static time_type add(const time_type& t, const duration_type& d) + { + const time_type epoch; + if (t >= epoch) + { + if ((time_type::max)() - t < d) + return (time_type::max)(); + } + else // t < epoch + { + if (-(t - (time_type::min)()) > d) + return (time_type::min)(); + } + + return t + d; + } + + // Subtract one time from another. + static duration_type subtract(const time_type& t1, const time_type& t2) + { + const time_type epoch; + if (t1 >= epoch) + { + if (t2 >= epoch) + { + return t1 - t2; + } + else if (t2 == (time_type::min)()) + { + return (duration_type::max)(); + } + else if ((time_type::max)() - t1 < epoch - t2) + { + return (duration_type::max)(); + } + else + { + return t1 - t2; + } + } + else // t1 < epoch + { + if (t2 < epoch) + { + return t1 - t2; + } + else if (t1 == (time_type::min)()) + { + return (duration_type::min)(); + } + else if ((time_type::max)() - t2 < epoch - t1) + { + return (duration_type::min)(); + } + else + { + return -(t2 - t1); + } + } + } + + // Test whether one time is less than another. + static bool less_than(const time_type& t1, const time_type& t2) + { + return t1 < t2; + } + + // Implement just enough of the posix_time::time_duration interface to supply + // what the timer_queue requires. + class posix_time_duration + { + public: + explicit posix_time_duration(const duration_type& d) + : d_(d) + { + } + + int64_t ticks() const + { + return d_.count(); + } + + int64_t total_seconds() const + { + return duration_cast<1, 1>(); + } + + int64_t total_milliseconds() const + { + return duration_cast<1, 1000>(); + } + + int64_t total_microseconds() const + { + return duration_cast<1, 1000000>(); + } + + private: + template + int64_t duration_cast() const + { + const int64_t num1 = period_type::num / gcd::value; + const int64_t num2 = Num / gcd::value; + + const int64_t den1 = period_type::den / gcd::value; + const int64_t den2 = Den / gcd::value; + + const int64_t num = num1 * den2; + const int64_t den = num2 * den1; + + if (num == 1 && den == 1) + return ticks(); + else if (num != 1 && den == 1) + return ticks() * num; + else if (num == 1 && period_type::den != 1) + return ticks() / den; + else + return ticks() * num / den; + } + + duration_type d_; + }; + + // Convert to POSIX duration type. + static posix_time_duration to_posix_duration(const duration_type& d) + { + return posix_time_duration(WaitTraits::to_wait_duration(d)); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/completion_handler.hpp b/extern/asio-1.18.2/include/asio/detail/completion_handler.hpp new file mode 100644 index 0000000..5c24fa4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/completion_handler.hpp @@ -0,0 +1,88 @@ +// +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_COMPLETION_HANDLER_HPP +#define ASIO_DETAIL_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class completion_handler : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(completion_handler); + + completion_handler(Handler& h, const IoExecutor& io_ex) + : operation(&completion_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + completion_handler* h(static_cast(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + + ASIO_HANDLER_COMPLETION((*h)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + h->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_)); + p.h = asio::detail::addressof(handler); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + w.complete(handler, handler); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/concurrency_hint.hpp b/extern/asio-1.18.2/include/asio/detail/concurrency_hint.hpp new file mode 100644 index 0000000..60ab2a8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/concurrency_hint.hpp @@ -0,0 +1,94 @@ +// +// detail/concurrency_hint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CONCURRENCY_HINT_HPP +#define ASIO_DETAIL_CONCURRENCY_HINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" + +// The concurrency hint ID and mask are used to identify when a "well-known" +// concurrency hint value has been passed to the io_context. +#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u +#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u + +// If set, this bit indicates that the scheduler should perform locking. +#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u + +// If set, this bit indicates that the reactor should perform locking when +// managing descriptor registrations. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u + +// If set, this bit indicates that the reactor should perform locking for I/O. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u + +// Helper macro to determine if we have a special concurrency hint. +#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \ + ((static_cast(hint) \ + & ASIO_CONCURRENCY_HINT_ID_MASK) \ + == ASIO_CONCURRENCY_HINT_ID) + +// Helper macro to determine if locking is enabled for a given facility. +#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \ + (((static_cast(hint) \ + & (ASIO_CONCURRENCY_HINT_ID_MASK \ + | ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \ + ^ ASIO_CONCURRENCY_HINT_ID) != 0) + +// This special concurrency hint disables locking in both the scheduler and +// reactor I/O. This hint has the following restrictions: +// +// - Care must be taken to ensure that all operations on the io_context and any +// of its associated I/O objects (such as sockets and timers) occur in only +// one thread at a time. +// +// - Asynchronous resolve operations fail with operation_not_supported. +// +// - If a signal_set is used with the io_context, signal_set objects cannot be +// used with any other io_context in the program. +#define ASIO_CONCURRENCY_HINT_UNSAFE \ + static_cast(ASIO_CONCURRENCY_HINT_ID) + +// This special concurrency hint disables locking in the reactor I/O. This hint +// has the following restrictions: +// +// - Care must be taken to ensure that run functions on the io_context, and all +// operations on the io_context's associated I/O objects (such as sockets and +// timers), occur in only one thread at a time. +#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \ + static_cast(ASIO_CONCURRENCY_HINT_ID \ + | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION) + +// The special concurrency hint provides full thread safety. +#define ASIO_CONCURRENCY_HINT_SAFE \ + static_cast(ASIO_CONCURRENCY_HINT_ID \ + | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO) + +// This #define may be overridden at compile time to specify a program-wide +// default concurrency hint, used by the zero-argument io_context constructor. +#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT) +# define ASIO_CONCURRENCY_HINT_DEFAULT -1 +#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT) + +// This #define may be overridden at compile time to specify a program-wide +// concurrency hint, used by the one-argument io_context constructor when +// passed a value of 1. +#if !defined(ASIO_CONCURRENCY_HINT_1) +# define ASIO_CONCURRENCY_HINT_1 1 +#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT) + +#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_event.hpp b/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_event.hpp new file mode 100644 index 0000000..bb5c524 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_event.hpp @@ -0,0 +1,120 @@ +// +// detail/conditionally_enabled_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP +#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/null_event.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_event + : private noncopyable +{ +public: + // Constructor. + conditionally_enabled_event() + { + } + + // Destructor. + ~conditionally_enabled_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + void signal(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal(lock); + } + + // Signal all waiters. + void signal_all(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal_all(lock); + } + + // Unlock the mutex and signal one waiter. + void unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + + // Unlock the mutex and signal one waiter who may destroy us. + void unlock_and_signal_one_for_destruction( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + + // If there's a waiter, unlock the mutex and signal it. + bool maybe_unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + return event_.maybe_unlock_and_signal_one(lock); + else + return false; + } + + // Reset the event. + void clear(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.clear(lock); + } + + // Wait for the event to become signalled. + void wait(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.wait(lock); + else + null_event().wait(lock); + } + + // Timed wait for the event to become signalled. + bool wait_for_usec( + conditionally_enabled_mutex::scoped_lock& lock, long usec) + { + if (lock.mutex_.enabled_) + return event_.wait_for_usec(lock, usec); + else + return null_event().wait_for_usec(lock, usec); + } + +private: + asio::detail::event event_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_mutex.hpp new file mode 100644 index 0000000..4f354ea --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/conditionally_enabled_mutex.hpp @@ -0,0 +1,149 @@ +// +// detail/conditionally_enabled_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP +#define ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_mutex + : private noncopyable +{ +public: + // Helper class to lock and unlock a mutex automatically. + class scoped_lock + : private noncopyable + { + public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t) + : mutex_(m), + locked_(m.enabled_) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(conditionally_enabled_mutex& m) + : mutex_(m) + { + if (m.enabled_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + else + locked_ = false; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (mutex_.enabled_ && !locked_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + asio::detail::mutex& mutex() + { + return mutex_.mutex_; + } + + private: + friend class conditionally_enabled_event; + conditionally_enabled_mutex& mutex_; + bool locked_; + }; + + // Constructor. + explicit conditionally_enabled_mutex(bool enabled) + : enabled_(enabled) + { + } + + // Destructor. + ~conditionally_enabled_mutex() + { + } + + // Determine whether locking is enabled. + bool enabled() const + { + return enabled_; + } + + // Lock the mutex. + void lock() + { + if (enabled_) + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + if (enabled_) + mutex_.unlock(); + } + +private: + friend class scoped_lock; + friend class conditionally_enabled_event; + asio::detail::mutex mutex_; + const bool enabled_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/config.hpp b/extern/asio-1.18.2/include/asio/detail/config.hpp new file mode 100644 index 0000000..a09cd17 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/config.hpp @@ -0,0 +1,1865 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CONFIG_HPP +#define ASIO_DETAIL_CONFIG_HPP + +// boostify: non-boost code starts here +#if !defined(ASIO_STANDALONE) +# if !defined(ASIO_ENABLE_BOOST) +# if (__cplusplus >= 201103) +# define ASIO_STANDALONE 1 +# elif defined(_MSC_VER) && defined(_MSVC_LANG) +# if (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103) +# define ASIO_STANDALONE 1 +# endif // (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103) +# endif // defined(_MSC_VER) && defined(_MSVC_LANG) +# endif // !defined(ASIO_ENABLE_BOOST) +#endif // !defined(ASIO_STANDALONE) + +// boostify: non-boost code ends here +#if defined(ASIO_STANDALONE) +# define ASIO_DISABLE_BOOST_ARRAY 1 +# define ASIO_DISABLE_BOOST_ASSERT 1 +# define ASIO_DISABLE_BOOST_BIND 1 +# define ASIO_DISABLE_BOOST_CHRONO 1 +# define ASIO_DISABLE_BOOST_DATE_TIME 1 +# define ASIO_DISABLE_BOOST_LIMITS 1 +# define ASIO_DISABLE_BOOST_REGEX 1 +# define ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(ASIO_STANDALONE) +# include +# include +# define ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either ASIO_SEPARATE_COMPILATION or +// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(ASIO_HEADER_ONLY) +# if !defined(ASIO_SEPARATE_COMPILATION) +# if !defined(ASIO_DYN_LINK) +# define ASIO_HEADER_ONLY 1 +# endif // !defined(ASIO_DYN_LINK) +# endif // !defined(ASIO_SEPARATE_COMPILATION) +#endif // !defined(ASIO_HEADER_ONLY) + +#if defined(ASIO_HEADER_ONLY) +# define ASIO_DECL inline +#else // defined(ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining ASIO_DYN_LINK. +# if defined(ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllexport) +# else // defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllimport) +# endif // defined(ASIO_SOURCE) +# endif // defined(ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(ASIO_HEADER_ONLY) + +// If ASIO_DECL isn't defined yet define it now. +#if !defined(ASIO_DECL) +# define ASIO_DECL +#endif // !defined(ASIO_DECL) + +// Helper macro for documentation. +#define ASIO_UNSPECIFIED(e) e + +// Microsoft Visual C++ detection. +#if !defined(ASIO_MSVC) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define ASIO_MSVC _MSC_VER +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Support move construction and assignment on compilers known to allow it. +#if !defined(ASIO_HAS_MOVE) +# if !defined(ASIO_DISABLE_MOVE) +# if defined(__clang__) +# if __has_feature(__cxx_rvalue_references__) +# define ASIO_HAS_MOVE 1 +# endif // __has_feature(__cxx_rvalue_references__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# if defined(__INTEL_CXX11_MODE__) +# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# define ASIO_HAS_MOVE 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# if defined(__ICL) && (__ICL >= 1500) +# define ASIO_HAS_MOVE 1 +# endif // defined(__ICL) && (__ICL >= 1500) +# endif // defined(__INTEL_CXX11_MODE__) +# endif // !defined(ASIO_DISABLE_MOVE) +#endif // !defined(ASIO_HAS_MOVE) + +// If ASIO_MOVE_CAST isn't defined, and move support is available, define +// * ASIO_MOVE_ARG, +// * ASIO_NONDEDUCED_MOVE_ARG, and +// * ASIO_MOVE_CAST +// to take advantage of rvalue references and perfect forwarding. +#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) +# define ASIO_MOVE_ARG(type) type&& +# define ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define ASIO_MOVE_CAST(type) static_cast +# define ASIO_MOVE_CAST2(type1, type2) static_cast +# define ASIO_MOVE_OR_LVALUE(type) static_cast +# define ASIO_MOVE_OR_LVALUE_TYPE(type) type +#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) + +// If ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible +// implementation. Note that older g++ and MSVC versions don't like it when you +// pass a non-member function through a const reference, so for most compilers +// we'll play it safe and stick with the old approach of passing the handler by +// value. +#if !defined(ASIO_MOVE_CAST) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define ASIO_MOVE_ARG(type) const type& +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define ASIO_MOVE_ARG(type) type +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1400) +# define ASIO_MOVE_ARG(type) const type& +# else // (_MSC_VER >= 1400) +# define ASIO_MOVE_ARG(type) type +# endif // (_MSC_VER >= 1400) +# else +# define ASIO_MOVE_ARG(type) type +# endif +# define ASIO_NONDEDUCED_MOVE_ARG(type) const type& +# define ASIO_MOVE_CAST(type) static_cast +# define ASIO_MOVE_CAST2(type1, type2) static_cast +# define ASIO_MOVE_OR_LVALUE(type) +# define ASIO_MOVE_OR_LVALUE_TYPE(type) type& +#endif // !defined(ASIO_MOVE_CAST) + +// Support variadic templates on compilers known to allow it. +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) +# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_variadic_templates__) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // __has_feature(__cxx_variadic_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) +#if !defined(ASIO_ELLIPSIS) +# if defined(ASIO_HAS_VARIADIC_TEMPLATES) +# define ASIO_ELLIPSIS ... +# else // defined(ASIO_HAS_VARIADIC_TEMPLATES) +# define ASIO_ELLIPSIS +# endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_ELLIPSIS) + +// Support deleted functions on compilers known to allow it. +#if !defined(ASIO_DELETED) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_DELETED = delete +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# endif // defined(__clang__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# if !defined(ASIO_DELETED) +# define ASIO_DELETED +# endif // !defined(ASIO_DELETED) +#endif // !defined(ASIO_DELETED) + +// Support constexpr on compilers known to allow it. +#if !defined(ASIO_HAS_CONSTEXPR) +# if !defined(ASIO_DISABLE_CONSTEXPR) +# if defined(__clang__) +# if __has_feature(__cxx_constexpr__) +# define ASIO_HAS_CONSTEXPR 1 +# endif // __has_feature(__cxx_constexpr__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CONSTEXPR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_CONSTEXPR 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CONSTEXPR) +#endif // !defined(ASIO_HAS_CONSTEXPR) +#if !defined(ASIO_CONSTEXPR) +# if defined(ASIO_HAS_CONSTEXPR) +# define ASIO_CONSTEXPR constexpr +# else // defined(ASIO_HAS_CONSTEXPR) +# define ASIO_CONSTEXPR +# endif // defined(ASIO_HAS_CONSTEXPR) +#endif // !defined(ASIO_CONSTEXPR) +#if !defined(ASIO_STATIC_CONSTEXPR) +# if defined(ASIO_HAS_CONSTEXPR) +# define ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# else // defined(ASIO_HAS_CONSTEXPR) +# define ASIO_STATIC_CONSTEXPR(type, assignment) \ + static const type assignment +# endif // defined(ASIO_HAS_CONSTEXPR) +#endif // !defined(ASIO_STATIC_CONSTEXPR) +#if !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(ASIO_HAS_CONSTEXPR) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# elif defined(ASIO_MSVC) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(ASIO_MSVC) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(ASIO_MSVC) +# else // defined(ASIO_HAS_CONSTEXPR) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // defined(ASIO_HAS_CONSTEXPR) +#endif // !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) + +// Support noexcept on compilers known to allow it. +#if !defined(ASIO_HAS_NOEXCEPT) +# if !defined(ASIO_DISABLE_NOEXCEPT) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# if !defined(BOOST_NO_NOEXCEPT) +# define ASIO_HAS_NOEXCEPT 1 +# endif // !defined(BOOST_NO_NOEXCEPT) +# define ASIO_NOEXCEPT BOOST_NOEXCEPT +# define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# define ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define ASIO_HAS_NOEXCEPT 1 +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_NOEXCEPT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_NOEXCEPT 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_NOEXCEPT) +# if !defined(ASIO_NOEXCEPT) +# endif // !defined(ASIO_NOEXCEPT) +# if !defined(ASIO_NOEXCEPT_OR_NOTHROW) +# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(ASIO_HAS_NOEXCEPT) +#if !defined(ASIO_NOEXCEPT) +# if defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT noexcept(true) +# else // defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT +# endif // defined(ASIO_HAS_NOEXCEPT) +#endif // !defined(ASIO_NOEXCEPT) +#if !defined(ASIO_NOEXCEPT_OR_NOTHROW) +# if defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# else // defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // defined(ASIO_HAS_NOEXCEPT) +#endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW) +#if !defined(ASIO_NOEXCEPT_IF) +# if defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT_IF(c) noexcept(c) +# else // defined(ASIO_HAS_NOEXCEPT) +# define ASIO_NOEXCEPT_IF(c) +# endif // defined(ASIO_HAS_NOEXCEPT) +#endif // !defined(ASIO_NOEXCEPT_IF) + +// Support automatic type deduction on compilers known to support it. +#if !defined(ASIO_HAS_DECLTYPE) +# if !defined(ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_DECLTYPE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_DECLTYPE) +#endif // !defined(ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(ASIO_HAS_ALIAS_TEMPLATES) + +// Support return type deduction on compilers known to allow it. +#if !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# endif // defined(__cpp_return_type_deduction) +# endif // !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support default function template arguments on compilers known to allow it. +#if !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if (__cplusplus >= 201103) +# define ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +#endif // !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +// Support concepts on compilers known to allow them. +#if !defined(ASIO_HAS_CONCEPTS) +# if !defined(ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(ASIO_DISABLE_CONCEPTS) +#endif // !defined(ASIO_HAS_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# endif // defined(__clang__) +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // defined(__clang__) +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# endif // !defined(ASIO_MSVC) && !defined(__INTEL_COMPILER) +# endif // !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support ref-qualified functions on compilers known to allow it. +#if !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +# if defined(__clang__) +# if __has_feature(__cxx_reference_qualified_functions__) +# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // __has_feature(__cxx_reference_qualified_functions__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +#endif // !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +#if defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(ASIO_LVALUE_REF_QUAL) +# define ASIO_LVALUE_REF_QUAL & +# endif // !defined(ASIO_LVALUE_REF_QUAL) +# if !defined(ASIO_RVALUE_REF_QUAL) +# define ASIO_RVALUE_REF_QUAL && +# endif // !defined(ASIO_RVALUE_REF_QUAL) +#else // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(ASIO_LVALUE_REF_QUAL) +# define ASIO_LVALUE_REF_QUAL +# endif // !defined(ASIO_LVALUE_REF_QUAL) +# if !defined(ASIO_RVALUE_REF_QUAL) +# define ASIO_RVALUE_REF_QUAL +# endif // !defined(ASIO_RVALUE_REF_QUAL) +#endif // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS) + +// Standard library support for system errors. +#if !defined(ASIO_HAS_STD_SYSTEM_ERROR) +# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) +#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR) + +// Compliant C++11 compilers put noexcept specifiers on error_category members. +#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +# define ASIO_ERROR_CATEGORY_NOEXCEPT +# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) + +// Standard library support for arrays. +#if !defined(ASIO_HAS_STD_ARRAY) +# if !defined(ASIO_DISABLE_STD_ARRAY) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ARRAY 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_ARRAY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ARRAY 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_ARRAY 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ARRAY) +#endif // !defined(ASIO_HAS_STD_ARRAY) + +// Standard library support for shared_ptr and weak_ptr. +#if !defined(ASIO_HAS_STD_SHARED_PTR) +# if !defined(ASIO_DISABLE_STD_SHARED_PTR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_SHARED_PTR 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR) +#endif // !defined(ASIO_HAS_STD_SHARED_PTR) + +// Standard library support for allocator_arg_t. +#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG) + +// Standard library support for atomic operations. +#if !defined(ASIO_HAS_STD_ATOMIC) +# if !defined(ASIO_DISABLE_STD_ATOMIC) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ATOMIC 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# if (__clang_major__ >= 10) +# if __has_include() +# define ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# endif // (__clang_major__ >= 10) +# endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ATOMIC 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_ATOMIC 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ATOMIC) +#endif // !defined(ASIO_HAS_STD_ATOMIC) + +// Standard library support for chrono. Some standard libraries (such as the +// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x +// drafts, rather than the eventually standardised name of steady_clock. +#if !defined(ASIO_HAS_STD_CHRONO) +# if !defined(ASIO_DISABLE_STD_CHRONO) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_CHRONO 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_CHRONO 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_CHRONO 1 +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_CHRONO 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_CHRONO) +#endif // !defined(ASIO_HAS_STD_CHRONO) + +// Boost support for chrono. +#if !defined(ASIO_HAS_BOOST_CHRONO) +# if !defined(ASIO_DISABLE_BOOST_CHRONO) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(ASIO_HAS_CHRONO) +# if defined(ASIO_HAS_STD_CHRONO) \ + || defined(ASIO_HAS_BOOST_CHRONO) +# define ASIO_HAS_CHRONO 1 +# endif // defined(ASIO_HAS_STD_CHRONO) + // || defined(ASIO_HAS_BOOST_CHRONO) +#endif // !defined(ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(ASIO_HAS_BOOST_DATE_TIME) +# if !defined(ASIO_DISABLE_BOOST_DATE_TIME) +# define ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(ASIO_HAS_BOOST_DATE_TIME) + +// Standard library support for addressof. +#if !defined(ASIO_HAS_STD_ADDRESSOF) +# if !defined(ASIO_DISABLE_STD_ADDRESSOF) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ADDRESSOF 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF) +#endif // !defined(ASIO_HAS_STD_ADDRESSOF) + +// Standard library support for the function class. +#if !defined(ASIO_HAS_STD_FUNCTION) +# if !defined(ASIO_DISABLE_STD_FUNCTION) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUNCTION 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_FUNCTION) +#endif // !defined(ASIO_HAS_STD_FUNCTION) + +// Standard library support for type traits. +#if !defined(ASIO_HAS_STD_TYPE_TRAITS) +# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS) +#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS) + +// Standard library support for the nullptr_t type. +#if !defined(ASIO_HAS_NULLPTR) +# if !defined(ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_nullptr__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_NULLPTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_NULLPTR) +#endif // !defined(ASIO_HAS_NULLPTR) + +// Standard library support for the C++11 allocator additions. +#if !defined(ASIO_HAS_CXX11_ALLOCATORS) +# if !defined(ASIO_DISABLE_CXX11_ALLOCATORS) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CXX11_ALLOCATORS) +#endif // !defined(ASIO_HAS_CXX11_ALLOCATORS) + +// Standard library support for the cstdint header. +#if !defined(ASIO_HAS_CSTDINT) +# if !defined(ASIO_DISABLE_CSTDINT) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_CSTDINT 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_CSTDINT 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CSTDINT) +#endif // !defined(ASIO_HAS_CSTDINT) + +// Standard library support for the thread class. +#if !defined(ASIO_HAS_STD_THREAD) +# if !defined(ASIO_DISABLE_STD_THREAD) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_THREAD 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_THREAD 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_THREAD 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_THREAD 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_THREAD) +#endif // !defined(ASIO_HAS_STD_THREAD) + +// Standard library support for the mutex and condition variable classes. +#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +// Standard library support for the call_once function. +#if !defined(ASIO_HAS_STD_CALL_ONCE) +# if !defined(ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(ASIO_HAS_STD_FUTURE) +# if !defined(ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define ASIO_HAS_STD_FUTURE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_FUTURE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_FUTURE) +#endif // !defined(ASIO_HAS_STD_FUTURE) + +// Standard library support for std::string_view. +#if !defined(ASIO_HAS_STD_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(ASIO_HAS_CLANG_LIBCXX) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(ASIO_HAS_STRING_VIEW) +# if !defined(ASIO_DISABLE_STRING_VIEW) +# if defined(ASIO_HAS_STD_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(ASIO_DISABLE_STRING_VIEW) +#endif // !defined(ASIO_HAS_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__GNUC__) +# if (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(ASIO_HAS_STD_IOSTREAM_MOVE) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT) + +// Standard library support for std::exception_ptr and std::current_exception. +#if !defined(ASIO_HAS_STD_EXCEPTION_PTR) +# if !defined(ASIO_DISABLE_STD_EXCEPTION_PTR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_EXCEPTION_PTR 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_EXCEPTION_PTR) +#endif // !defined(ASIO_HAS_STD_EXCEPTION_PTR) + +// Standard library support for std::nested_exception. +#if !defined(ASIO_HAS_STD_NESTED_EXCEPTION) +# if !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_NESTED_EXCEPTION 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION) +#endif // !defined(ASIO_HAS_STD_NESTED_EXCEPTION) + +// Standard library support for std::any. +#if !defined(ASIO_HAS_STD_ANY) +# if !defined(ASIO_DISABLE_STD_ANY) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define ASIO_HAS_STD_ANY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ANY) +#endif // !defined(ASIO_HAS_STD_ANY) + +// Standard library support for std::source_location. +#if !defined(ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(ASIO_HAS_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_SOURCE_LOCATION) +# if defined(ASIO_HAS_STD_SOURCE_LOCATION) +# define ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_SOURCE_LOCATION) + +// Windows App target. Windows but with a limited API. +#if !defined(ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(ASIO_WINDOWS_RUNTIME) +# if !defined(ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(ASIO_WINDOWS_APP) +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(ASIO_WINDOWS) +# if !defined(ASIO_WINDOWS_RUNTIME) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define ASIO_WINDOWS 1 +# elif defined(ASIO_WINDOWS_APP) +# define ASIO_WINDOWS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(ASIO_NO_NOMINMAX) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(ASIO_HAS_IOCP) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# if !defined(ASIO_DISABLE_IOCP) +# define ASIO_HAS_IOCP 1 +# endif // !defined(ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(ASIO_HAS_UNISTD_H) +# if !defined(ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(ASIO_HAS_BOOST_CONFIG) +#endif // !defined(ASIO_HAS_UNISTD_H) +#if defined(ASIO_HAS_UNISTD_H) +# include +#endif // defined(ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(ASIO_HAS_EPOLL) +# if !defined(ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(ASIO_DISABLE_EPOLL) +# endif // !defined(ASIO_HAS_EPOLL) +# if !defined(ASIO_HAS_EVENTFD) +# if !defined(ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(ASIO_DISABLE_EVENTFD) +# endif // !defined(ASIO_HAS_EVENTFD) +# if !defined(ASIO_HAS_TIMERFD) +# if defined(ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(ASIO_HAS_EPOLL) +# endif // !defined(ASIO_HAS_TIMERFD) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(ASIO_HAS_KQUEUE) +# if !defined(ASIO_DISABLE_KQUEUE) +# define ASIO_HAS_KQUEUE 1 +# endif // !defined(ASIO_DISABLE_KQUEUE) +# endif // !defined(ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(ASIO_HAS_DEV_POLL) +# if !defined(ASIO_DISABLE_DEV_POLL) +# define ASIO_HAS_DEV_POLL 1 +# endif // !defined(ASIO_DISABLE_DEV_POLL) +# endif // !defined(ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(ASIO_HAS_SERIAL_PORT) +# if defined(ASIO_HAS_IOCP) \ + || !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(ASIO_DISABLE_SERIAL_PORT) +# define ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(ASIO_HAS_IOCP) + // || !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# define ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(ASIO_HAS_LOCAL_SOCKETS) +# if !defined(ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(ASIO_WINDOWS_RUNTIME) +# define ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(ASIO_WINDOWS_RUNTIME) +# endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(ASIO_HAS_LOCAL_SOCKETS) + +// Can use sigaction() instead of signal(). +#if !defined(ASIO_HAS_SIGACTION) +# if !defined(ASIO_DISABLE_SIGACTION) +# if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define ASIO_HAS_SIGACTION 1 +# endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_SIGACTION) +#endif // !defined(ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(ASIO_HAS_SIGNAL) +# if !defined(ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(ASIO_DISABLE_SIGNAL) +#endif // !defined(ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(ASIO_HAS_GETADDRINFO) +# if !defined(ASIO_DISABLE_GETADDRINFO) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(ASIO_DISABLE_GETADDRINFO) +#endif // !defined(ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(ASIO_NO_IOSTREAM) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(ASIO_NO_EXCEPTIONS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(ASIO_NO_TYPEID) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(ASIO_NO_TYPEID) + +// Threads. +#if !defined(ASIO_HAS_THREADS) +# if !defined(ASIO_DISABLE_THREADS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define ASIO_HAS_THREADS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(ASIO_DISABLE_THREADS) +#endif // !defined(ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(ASIO_HAS_PTHREADS) +# if defined(ASIO_HAS_THREADS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define ASIO_HAS_PTHREADS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(ASIO_HAS_THREADS) +#endif // !defined(ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(ASIO_STATIC_CONSTANT) +# if !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(ASIO_STATIC_CONSTANT) + +// Boost array library. +#if !defined(ASIO_HAS_BOOST_ARRAY) +# if !defined(ASIO_DISABLE_BOOST_ARRAY) +# define ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(ASIO_HAS_BOOST_ASSERT) +# if !defined(ASIO_DISABLE_BOOST_ASSERT) +# define ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(ASIO_HAS_BOOST_LIMITS) +# if !defined(ASIO_DISABLE_BOOST_LIMITS) +# define ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(ASIO_HAS_BOOST_REGEX) +# if !defined(ASIO_DISABLE_BOOST_REGEX) +# define ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(ASIO_HAS_BOOST_BIND) +# if !defined(ASIO_DISABLE_BOOST_BIND) +# define ASIO_HAS_BOOST_BIND 1 +# endif // !defined(ASIO_DISABLE_BOOST_BIND) +#endif // !defined(ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(ASIO_HAS_BOOST_WORKAROUND) +# if !defined(ASIO_DISABLE_BOOST_WORKAROUND) +# define ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(ASIO_HAS_SECURE_RTL) +# if !defined(ASIO_DISABLE_SECURE_RTL) +# if defined(ASIO_MSVC) \ + && (ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define ASIO_HAS_SECURE_RTL 1 +# endif // defined(ASIO_MSVC) + // && (ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(ASIO_DISABLE_SECURE_RTL) +#endif // !defined(ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(ASIO_HAS_HANDLER_HOOKS) +# if !defined(ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) || defined(__clang__) +# define ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) || defined(__clang__) +# endif // !defined(ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension. +#if !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(ASIO_THREAD_KEYWORD) +# define ASIO_THREAD_KEYWORD __thread +#endif // !defined(ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(ASIO_NO_DEPRECATED) +# define ASIO_SYNC_OP_VOID void +# define ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(ASIO_NO_DEPRECATED) +# define ASIO_SYNC_OP_VOID asio::error_code +# define ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_TYPEDEF) +# define ASIO_UNUSED_TYPEDEF +#endif // !defined(ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_VARIABLE) +# define ASIO_UNUSED_VARIABLE +#endif // !defined(ASIO_UNUSED_VARIABLE) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(ASIO_HAS_CO_AWAIT) +# if !defined(ASIO_DISABLE_CO_AWAIT) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# endif // defined(ASIO_MSVC) +# if defined(__clang__) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_CO_AWAIT) +#endif // !defined(ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(ASIO_HAS_STD_COROUTINE) +# if !defined(ASIO_DISABLE_STD_COROUTINE) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# endif // defined(ASIO_MSVC) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(ASIO_NODISCARD) +#if !defined(ASIO_NODISCARD) +# define ASIO_NODISCARD +#endif // !defined(ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::hash. +#if !defined(ASIO_HAS_STD_HASH) +# if !defined(ASIO_DISABLE_STD_HASH) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_HASH 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_HASH 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_HASH) +#endif // !defined(ASIO_HAS_STD_HASH) + +#endif // ASIO_DETAIL_CONFIG_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/consuming_buffers.hpp b/extern/asio-1.18.2/include/asio/detail/consuming_buffers.hpp new file mode 100644 index 0000000..0d99093 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/consuming_buffers.hpp @@ -0,0 +1,414 @@ +// +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CONSUMING_BUFFERS_HPP +#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/buffer.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/limits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper template to determine the maximum number of prepared buffers. +template +struct prepared_buffers_max +{ + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template +struct prepared_buffers_max > +{ + enum { value = N }; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template +struct prepared_buffers_max > +{ + enum { value = N }; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// A buffer sequence used to represent a subsequence of the buffers. +template +struct prepared_buffers +{ + typedef Buffer value_type; + typedef const Buffer* const_iterator; + + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; + + prepared_buffers() : count(0) {} + const_iterator begin() const { return elems; } + const_iterator end() const { return elems + count; } + + Buffer elems[max_buffers]; + std::size_t count; +}; + +// A proxy for a sub-range in a list of buffers. +template +class consuming_buffers +{ +public: + typedef prepared_buffers::value> + prepared_buffers_type; + + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + total_consumed_(0), + next_elem_(0), + next_elem_offset_(0) + { + using asio::buffer_size; + total_size_ = buffer_size(buffers); + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= total_size_; + } + + // Get the buffer for a single transfer, with a size. + prepared_buffers_type prepare(std::size_t max_size) + { + prepared_buffers_type result; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + std::size_t elem_offset = next_elem_offset_; + while (next != end && max_size > 0 && (result.count) < result.max_buffers) + { + Buffer next_buf = Buffer(*next) + elem_offset; + result.elems[result.count] = asio::buffer(next_buf, max_size); + max_size -= result.elems[result.count].size(); + elem_offset = 0; + if (result.elems[result.count].size() > 0) + ++result.count; + ++next; + } + + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + while (next != end && size > 0) + { + Buffer next_buf = Buffer(*next) + next_elem_offset_; + if (size < next_buf.size()) + { + next_elem_offset_ += size; + size = 0; + } + else + { + size -= next_buf.size(); + next_elem_offset_ = 0; + ++next_elem_; + ++next; + } + } + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffers buffers_; + std::size_t total_size_; + std::size_t total_consumed_; + std::size_t next_elem_; + std::size_t next_elem_offset_; +}; + +// Base class of all consuming_buffers specialisations for single buffers. +template +class consuming_single_buffer +{ +public: + // Construct to represent the entire list of buffers. + template + explicit consuming_single_buffer(const Buffer1& buffer) + : buffer_(buffer), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= buffer_.size(); + } + + // Get the buffer for a single transfer, with a size. + Buffer prepare(std::size_t max_size) + { + return asio::buffer(buffer_ + total_consumed_, max_size); + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffer buffer_; + std::size_t total_consumed_; +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const const_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const const_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template +class consuming_buffers, + typename boost::array::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const boost::array& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + boost::array prepare(std::size_t max_size) + { + boost::array result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + boost::array buffers_; + std::size_t total_consumed_; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template +class consuming_buffers, + typename std::array::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const std::array& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + std::array prepare(std::size_t max_size) + { + std::array result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + std::array buffers_; + std::size_t total_consumed_; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// Specialisation for null_buffers to ensure that the null_buffers type is +// always passed through to the underlying read or write operation. +template +class consuming_buffers + : public asio::null_buffers +{ +public: + consuming_buffers(const null_buffers&) + { + // No-op. + } + + bool empty() + { + return false; + } + + null_buffers prepare(std::size_t) + { + return null_buffers(); + } + + void consume(std::size_t) + { + // No-op. + } + + std::size_t total_consumed() const + { + return 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/cstddef.hpp b/extern/asio-1.18.2/include/asio/detail/cstddef.hpp new file mode 100644 index 0000000..e9fd2d2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/cstddef.hpp @@ -0,0 +1,31 @@ +// +// detail/cstddef.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CSTDDEF_HPP +#define ASIO_DETAIL_CSTDDEF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include + +namespace asio { + +#if defined(ASIO_HAS_NULLPTR) +using std::nullptr_t; +#else // defined(ASIO_HAS_NULLPTR) +struct nullptr_t {}; +#endif // defined(ASIO_HAS_NULLPTR) + +} // namespace asio + +#endif // ASIO_DETAIL_CSTDDEF_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/cstdint.hpp b/extern/asio-1.18.2/include/asio/detail/cstdint.hpp new file mode 100644 index 0000000..d29929b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/cstdint.hpp @@ -0,0 +1,60 @@ +// +// detail/cstdint.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_CSTDINT_HPP +#define ASIO_DETAIL_CSTDINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CSTDINT) +# include +#else // defined(ASIO_HAS_CSTDINT) +# include +#endif // defined(ASIO_HAS_CSTDINT) + +namespace asio { + +#if defined(ASIO_HAS_CSTDINT) +using std::int16_t; +using std::int_least16_t; +using std::uint16_t; +using std::uint_least16_t; +using std::int32_t; +using std::int_least32_t; +using std::uint32_t; +using std::uint_least32_t; +using std::int64_t; +using std::int_least64_t; +using std::uint64_t; +using std::uint_least64_t; +using std::uintmax_t; +#else // defined(ASIO_HAS_CSTDINT) +using boost::int16_t; +using boost::int_least16_t; +using boost::uint16_t; +using boost::uint_least16_t; +using boost::int32_t; +using boost::int_least32_t; +using boost::uint32_t; +using boost::uint_least32_t; +using boost::int64_t; +using boost::int_least64_t; +using boost::uint64_t; +using boost::uint_least64_t; +using boost::uintmax_t; +#endif // defined(ASIO_HAS_CSTDINT) + +} // namespace asio + +#endif // ASIO_DETAIL_CSTDINT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/date_time_fwd.hpp b/extern/asio-1.18.2/include/asio/detail/date_time_fwd.hpp new file mode 100644 index 0000000..1b21022 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/date_time_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/date_time_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DATE_TIME_FWD_HPP +#define ASIO_DETAIL_DATE_TIME_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace boost { +namespace date_time { + +template +class base_time; + +} // namespace date_time +namespace posix_time { + +class ptime; + +} // namespace posix_time +} // namespace boost + +#endif // ASIO_DETAIL_DATE_TIME_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/deadline_timer_service.hpp b/extern/asio-1.18.2/include/asio/detail/deadline_timer_service.hpp new file mode 100644 index 0000000..262651e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/deadline_timer_service.hpp @@ -0,0 +1,295 @@ +// +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP +#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue.hpp" +#include "asio/detail/timer_queue_ptime.hpp" +#include "asio/detail/timer_scheduler.hpp" +#include "asio/detail/wait_handler.hpp" +#include "asio/detail/wait_op.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include +# include +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class deadline_timer_service + : public execution_context_service_base > +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // The implementation type of the timer. This type is dependent on the + // underlying implementation of the timer service. + struct implementation_type + : private asio::detail::noncopyable + { + time_type expiry; + bool might_have_pending_waits; + typename timer_queue::per_timer_data timer_data; + }; + + // Constructor. + deadline_timer_service(execution_context& context) + : execution_context_service_base< + deadline_timer_service >(context), + scheduler_(asio::use_service(context)) + { + scheduler_.init_task(); + scheduler_.add_timer_queue(timer_queue_); + } + + // Destructor. + ~deadline_timer_service() + { + scheduler_.remove_timer_queue(timer_queue_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new timer implementation. + void construct(implementation_type& impl) + { + impl.expiry = time_type(); + impl.might_have_pending_waits = false; + } + + // Destroy a timer implementation. + void destroy(implementation_type& impl) + { + asio::error_code ec; + cancel(impl, ec); + } + + // Move-construct a new timer implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-assign from another timer implementation. + void move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + if (this != &other_service) + if (impl.might_have_pending_waits) + scheduler_.cancel_timer(timer_queue_, impl.timer_data); + + other_service.scheduler_.move_timer(other_service.timer_queue_, + impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-construct a new timer implementation. + void converting_move_construct(implementation_type& impl, + deadline_timer_service&, implementation_type& other_impl) + { + move_construct(impl, other_impl); + } + + // Move-assign from another timer implementation. + void converting_move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + move_assign(impl, other_service, other_impl); + } + + // Cancel any asynchronous wait operations associated with the timer. + std::size_t cancel(implementation_type& impl, asio::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = asio::error_code(); + return 0; + } + + ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel")); + + std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); + impl.might_have_pending_waits = false; + ec = asio::error_code(); + return count; + } + + // Cancels one asynchronous wait operation associated with the timer. + std::size_t cancel_one(implementation_type& impl, + asio::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = asio::error_code(); + return 0; + } + + ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel_one")); + + std::size_t count = scheduler_.cancel_timer( + timer_queue_, impl.timer_data, 1); + if (count == 0) + impl.might_have_pending_waits = false; + ec = asio::error_code(); + return count; + } + + // Get the expiry time for the timer as an absolute time. + time_type expiry(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer as an absolute time. + time_type expires_at(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return Time_Traits::subtract(this->expiry(impl), Time_Traits::now()); + } + + // Set the expiry time for the timer as an absolute time. + std::size_t expires_at(implementation_type& impl, + const time_type& expiry_time, asio::error_code& ec) + { + std::size_t count = cancel(impl, ec); + impl.expiry = expiry_time; + ec = asio::error_code(); + return count; + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration_type& expiry_time, asio::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_from_now(implementation_type& impl, + const duration_type& expiry_time, asio::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Perform a blocking wait on the timer. + void wait(implementation_type& impl, asio::error_code& ec) + { + time_type now = Time_Traits::now(); + ec = asio::error_code(); + while (Time_Traits::less_than(now, impl.expiry) && !ec) + { + this->do_wait(Time_Traits::to_posix_duration( + Time_Traits::subtract(impl.expiry, now)), ec); + now = Time_Traits::now(); + } + } + + // Start an asynchronous wait on the timer. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + impl.might_have_pending_waits = true; + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "deadline_timer", &impl, 0, "async_wait")); + + scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to wait given a duration type. The duration type should + // either be of type boost::posix_time::time_duration, or implement the + // required subset of its interface. + template + void do_wait(const Duration& timeout, asio::error_code& ec) + { +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for( + std::chrono::seconds(timeout.total_seconds()) + + std::chrono::microseconds(timeout.total_microseconds())); + ec = asio::error_code(); +#else // defined(ASIO_WINDOWS_RUNTIME) + ::timeval tv; + tv.tv_sec = timeout.total_seconds(); + tv.tv_usec = timeout.total_microseconds() % 1000000; + socket_ops::select(0, 0, 0, 0, &tv, ec); +#endif // defined(ASIO_WINDOWS_RUNTIME) + } + + // The queue of timers. + timer_queue timer_queue_; + + // The object that schedules and executes timers. Usually a reactor. + timer_scheduler& scheduler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/dependent_type.hpp b/extern/asio-1.18.2/include/asio/detail/dependent_type.hpp new file mode 100644 index 0000000..bcdfff3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/dependent_type.hpp @@ -0,0 +1,36 @@ +// +// detail/dependent_type.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DEPENDENT_TYPE_HPP +#define ASIO_DETAIL_DEPENDENT_TYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct dependent_type +{ + typedef T type; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEPENDENT_TYPE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/descriptor_ops.hpp b/extern/asio-1.18.2/include/asio/detail/descriptor_ops.hpp new file mode 100644 index 0000000..384aa8d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/descriptor_ops.hpp @@ -0,0 +1,139 @@ +// +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DESCRIPTOR_OPS_HPP +#define ASIO_DETAIL_DESCRIPTOR_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace descriptor_ops { + +// Descriptor state bits. +enum +{ + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // The descriptor may have been dup()-ed. + possible_dup = 4 +}; + +typedef unsigned char state_type; + +inline void get_last_error( + asio::error_code& ec, bool is_error_condition) +{ + if (!is_error_condition) + { + ec.assign(0, ec.category()); + } + else + { + ec = asio::error_code(errno, + asio::error::get_system_category()); + } +} + +ASIO_DECL int open(const char* path, int flags, + asio::error_code& ec); + +ASIO_DECL int close(int d, state_type& state, + asio::error_code& ec); + +ASIO_DECL bool set_user_non_blocking(int d, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, bool value, asio::error_code& ec); + +typedef iovec buf; + +ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec); + +ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, asio::error_code& ec); + +ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec); + +ASIO_DECL std::size_t sync_write1(int d, state_type state, + const void* data, std::size_t size, asio::error_code& ec); + +ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_write1(int d, + const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec); + +ASIO_DECL int fcntl(int d, int cmd, asio::error_code& ec); + +ASIO_DECL int fcntl(int d, int cmd, + long arg, asio::error_code& ec); + +ASIO_DECL int poll_read(int d, + state_type state, asio::error_code& ec); + +ASIO_DECL int poll_write(int d, + state_type state, asio::error_code& ec); + +ASIO_DECL int poll_error(int d, + state_type state, asio::error_code& ec); + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/descriptor_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/descriptor_read_op.hpp b/extern/asio-1.18.2/include/asio/detail/descriptor_read_op.hpp new file mode 100644 index 0000000..edc8d34 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,148 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(const asio::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_read1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template +class descriptor_read_op + : public descriptor_read_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(const asio::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_read_op_base(success_ec, + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/descriptor_write_op.hpp b/extern/asio-1.18.2/include/asio/detail/descriptor_write_op.hpp new file mode 100644 index 0000000..c2bc867 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,148 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(const asio::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_write1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template +class descriptor_write_op + : public descriptor_write_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(const asio::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_write_op_base(success_ec, + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/dev_poll_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/dev_poll_reactor.hpp new file mode 100644 index 0000000..f9e2f5a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/dev_poll_reactor.hpp @@ -0,0 +1,218 @@ +// +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include +#include +#include +#include "asio/detail/hash_map.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class dev_poll_reactor + : public execution_context_service_base +{ +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + ASIO_DECL dev_poll_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~dev_poll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run /dev/poll once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: + // Create the /dev/poll file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the /dev/poll DP_POLL operation. The timeout + // value is returned as a number of milliseconds. A return value of -1 + // indicates that the poll should block indefinitely. + ASIO_DECL int get_timeout(int msec); + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the dev_poll_reactor's mutex. + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); + + // Add a pending event entry for the given descriptor. + ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // The /dev/poll file descriptor. + int dev_poll_fd_; + + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map pending_event_change_index_; + + // The interrupter is used to break a blocking DP_POLL operation. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/dev_poll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/dev_poll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/epoll_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/epoll_reactor.hpp new file mode 100644 index 0000000..af8ffe4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/epoll_reactor.hpp @@ -0,0 +1,266 @@ +// +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_EPOLL_REACTOR_HPP +#define ASIO_DETAIL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EPOLL) + +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/object_pool.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_TIMERFD) +# include +#endif // defined(ASIO_HAS_TIMERFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class epoll_reactor + : public execution_context_service_base +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + class descriptor_state : operation + { + friend class epoll_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + epoll_reactor* reactor_; + int descriptor_; + uint32_t registered_events_; + op_queue op_queue_[max_ops]; + bool try_speculative_[max_ops]; + bool shutdown_; + + ASIO_DECL descriptor_state(bool locking); + void set_ready_events(uint32_t events) { task_result_ = events; } + void add_ready_events(uint32_t events) { task_result_ |= events; } + ASIO_DECL operation* perform_io(uint32_t events); + ASIO_DECL static void do_complete( + void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred); + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + ASIO_DECL epoll_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~epoll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run epoll once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: + // The hint to pass to epoll_create to size its data structures. + enum { epoll_size = 20000 }; + + // Create the epoll file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_epoll_create(); + + // Create the timerfd file descriptor. Does not throw. + ASIO_DECL static int do_timerfd_create(); + + // Allocate a new descriptor state object. + ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); + + // Get the timeout value for the epoll_wait call. The timeout value is + // returned as a number of milliseconds. A return value of -1 indicates + // that epoll_wait should block indefinitely. + ASIO_DECL int get_timeout(int msec); + +#if defined(ASIO_HAS_TIMERFD) + // Get the timeout value for the timer descriptor. The return value is the + // flag argument to be used when calling timerfd_settime. + ASIO_DECL int get_timeout(itimerspec& ts); +#endif // defined(ASIO_HAS_TIMERFD) + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The interrupter is used to break a blocking epoll_wait call. + select_interrupter interrupter_; + + // The epoll file descriptor. + int epoll_fd_; + + // The timer file descriptor. + int timer_fd_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool registered_descriptors_; + + // Helper class to do post-perform_io cleanup. + struct perform_io_cleanup_on_block_exit; + friend struct perform_io_cleanup_on_block_exit; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/epoll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/epoll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/event.hpp b/extern/asio-1.18.2/include/asio/detail/event.hpp new file mode 100644 index 0000000..d2b850a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/event.hpp @@ -0,0 +1,48 @@ +// +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_EVENT_HPP +#define ASIO_DETAIL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_event.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_event.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_event.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_event.hpp" +#else +# error Only Windows, POSIX and std::condition_variable are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_event event; +#elif defined(ASIO_WINDOWS) +typedef win_event event; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_event event; +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_event event; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/eventfd_select_interrupter.hpp b/extern/asio-1.18.2/include/asio/detail/eventfd_select_interrupter.hpp new file mode 100644 index 0000000..964e90c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/eventfd_select_interrupter.hpp @@ -0,0 +1,83 @@ +// +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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 ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EVENTFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class eventfd_select_interrupter +{ +public: + // Constructor. + ASIO_DECL eventfd_select_interrupter(); + + // Destructor. + ASIO_DECL ~eventfd_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupter. Returns true if the reset was successful. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // 64bit value will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // 64bit non-zero value may be written to this to wake up the select which is + // waiting for the other end to become readable. This descriptor will only + // differ from the read descriptor when a pipe is used. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/eventfd_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EVENTFD) + +#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/executor_function.hpp b/extern/asio-1.18.2/include/asio/detail/executor_function.hpp new file mode 100644 index 0000000..6b24f3a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/executor_function.hpp @@ -0,0 +1,204 @@ +// +// detail/executor_function.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_EXECUTOR_FUNCTION_HPP +#define ASIO_DETAIL_EXECUTOR_FUNCTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_MOVE) + +// Lightweight, move-only function object wrapper. +class executor_function +{ +public: + template + explicit executor_function(F f, const Alloc& a) + { + // Allocate and construct an object to wrap the function. + typedef impl impl_type; + typename impl_type::ptr p = { + detail::addressof(a), impl_type::ptr::allocate(a), 0 }; + impl_ = new (p.v) impl_type(ASIO_MOVE_CAST(F)(f), a); + p.v = 0; + } + + executor_function(executor_function&& other) ASIO_NOEXCEPT + : impl_(other.impl_) + { + other.impl_ = 0; + } + + ~executor_function() + { + if (impl_) + impl_->complete_(impl_, false); + } + + void operator()() + { + if (impl_) + { + impl_base* i = impl_; + impl_ = 0; + i->complete_(i, true); + } + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*complete_)(impl_base*, bool); + }; + + // Polymorphic function implementation. + template + struct impl : impl_base + { + ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( + thread_info_base::executor_function_tag, impl); + + template + impl(ASIO_MOVE_ARG(F) f, const Alloc& a) + : function_(ASIO_MOVE_CAST(F)(f)), + allocator_(a) + { + complete_ = &executor_function::complete; + } + + Function function_; + Alloc allocator_; + }; + + // Helper to complete function invocation. + template + static void complete(impl_base* base, bool call) + { + // Take ownership of the function object. + impl* i(static_cast*>(base)); + Alloc allocator(i->allocator_); + typename impl::ptr p = { + detail::addressof(allocator), i, i }; + + // Make a copy of the function so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the function may be the true owner of the memory + // associated with the function. Consequently, a local copy of the function + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Function function(ASIO_MOVE_CAST(Function)(i->function_)); + p.reset(); + + // Make the upcall if required. + if (call) + { + asio_handler_invoke_helpers::invoke(function, function); + } + } + + impl_base* impl_; +}; + +#else // defined(ASIO_HAS_MOVE) + +// Not so lightweight, copyable function object wrapper. +class executor_function +{ +public: + template + explicit executor_function(const F& f, const Alloc&) + : impl_(new impl::type>(f)) + { + } + + void operator()() + { + impl_->complete_(impl_.get()); + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*complete_)(impl_base*); + }; + + // Polymorphic function implementation. + template + struct impl : impl_base + { + impl(const F& f) + : function_(f) + { + complete_ = &executor_function::complete; + } + + F function_; + }; + + // Helper to complete function invocation. + template + static void complete(impl_base* i) + { + static_cast*>(i)->function_(); + } + + shared_ptr impl_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +// Lightweight, non-owning, copyable function object wrapper. +class executor_function_view +{ +public: + template + explicit executor_function_view(F& f) ASIO_NOEXCEPT + : complete_(&executor_function_view::complete), + function_(&f) + { + } + + void operator()() + { + complete_(function_); + } + +private: + // Helper to complete function invocation. + template + static void complete(void* f) + { + (*static_cast(f))(); + } + + void (*complete_)(void*); + void* function_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_EXECUTOR_FUNCTION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/executor_op.hpp b/extern/asio-1.18.2/include/asio/detail/executor_op.hpp new file mode 100644 index 0000000..f97618c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/executor_op.hpp @@ -0,0 +1,84 @@ +// +// detail/executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_EXECUTOR_OP_HPP +#define ASIO_DETAIL_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/scheduler_operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class executor_op : public Operation +{ +public: + ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); + + template + executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator) + : Operation(&executor_op::do_complete), + handler_(ASIO_MOVE_CAST(H)(h)), + allocator_(allocator) + { + } + + static void do_complete(void* owner, Operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + executor_op* o(static_cast(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_)); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + asio_handler_invoke_helpers::invoke(handler, handler); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + Alloc allocator_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_EXECUTOR_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/fd_set_adapter.hpp b/extern/asio-1.18.2/include/asio/detail/fd_set_adapter.hpp new file mode 100644 index 0000000..ade20ca --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/fd_set_adapter.hpp @@ -0,0 +1,39 @@ +// +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/posix_fd_set_adapter.hpp" +#include "asio/detail/win_fd_set_adapter.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef win_fd_set_adapter fd_set_adapter; +#else +typedef posix_fd_set_adapter fd_set_adapter; +#endif + +} // namespace detail +} // namespace asio + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/fenced_block.hpp new file mode 100644 index 0000000..08e47d6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/fenced_block.hpp @@ -0,0 +1,80 @@ +// +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_FENCED_BLOCK_HPP +#define ASIO_DETAIL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) +# include "asio/detail/null_fenced_block.hpp" +#elif defined(ASIO_HAS_STD_ATOMIC) +# include "asio/detail/std_fenced_block.hpp" +#elif defined(__MACH__) && defined(__APPLE__) +# include "asio/detail/macos_fenced_block.hpp" +#elif defined(__sun) +# include "asio/detail/solaris_fenced_block.hpp" +#elif defined(__GNUC__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +# include "asio/detail/gcc_arm_fenced_block.hpp" +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +# include "asio/detail/gcc_hppa_fenced_block.hpp" +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# include "asio/detail/gcc_x86_fenced_block.hpp" +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +# include "asio/detail/gcc_sync_fenced_block.hpp" +#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) +# include "asio/detail/win_fenced_block.hpp" +#else +# include "asio/detail/null_fenced_block.hpp" +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) +typedef null_fenced_block fenced_block; +#elif defined(ASIO_HAS_STD_ATOMIC) +typedef std_fenced_block fenced_block; +#elif defined(__MACH__) && defined(__APPLE__) +typedef macos_fenced_block fenced_block; +#elif defined(__sun) +typedef solaris_fenced_block fenced_block; +#elif defined(__GNUC__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +typedef gcc_arm_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +typedef gcc_hppa_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +typedef gcc_x86_fenced_block fenced_block; +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +typedef gcc_sync_fenced_block fenced_block; +#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) +typedef win_fenced_block fenced_block; +#else +typedef null_fenced_block fenced_block; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/functional.hpp b/extern/asio-1.18.2/include/asio/detail/functional.hpp new file mode 100644 index 0000000..c4cfc39 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/functional.hpp @@ -0,0 +1,38 @@ +// +// detail/functional.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_FUNCTIONAL_HPP +#define ASIO_DETAIL_FUNCTIONAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include + +#if !defined(ASIO_HAS_STD_FUNCTION) +# include +#endif // !defined(ASIO_HAS_STD_FUNCTION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_FUNCTION) +using std::function; +#else // defined(ASIO_HAS_STD_FUNCTION) +using boost::function; +#endif // defined(ASIO_HAS_STD_FUNCTION) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_FUNCTIONAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/future.hpp b/extern/asio-1.18.2/include/asio/detail/future.hpp new file mode 100644 index 0000000..9fe828e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/future.hpp @@ -0,0 +1,33 @@ +// +// detail/future.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_FUTURE_HPP +#define ASIO_DETAIL_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_HAS_STD_FUTURE) +# include +// Even though the future header is available, libstdc++ may not implement the +// std::future class itself. However, we need to have already included the +// future header to reliably test for _GLIBCXX_HAS_GTHREADS. +# if defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) +# if defined(_GLIBCXX_HAS_GTHREADS) +# define ASIO_HAS_STD_FUTURE_CLASS 1 +# endif // defined(_GLIBCXX_HAS_GTHREADS) +# else // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUTURE_CLASS 1 +# endif // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) +#endif // defined(ASIO_HAS_STD_FUTURE) + +#endif // ASIO_DETAIL_FUTURE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/gcc_arm_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/gcc_arm_fenced_block.hpp new file mode 100644 index 0000000..c879c22 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/gcc_arm_fenced_block.hpp @@ -0,0 +1,91 @@ +// +// detail/gcc_arm_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && defined(__arm__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_arm_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_arm_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_arm_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_arm_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) +# if defined(__thumb__) + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); +# else // defined(__thumb__) + int a = 0, b = 0; + __asm__ __volatile__ ("swp %0, %1, [%2]" + : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); +# endif // defined(__thumb__) +#else + // ARMv7 and later. + __asm__ __volatile__ ("dmb" : : : "memory"); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && defined(__arm__) + +#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/gcc_hppa_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/gcc_hppa_fenced_block.hpp new file mode 100644 index 0000000..38caa4b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/gcc_hppa_fenced_block.hpp @@ -0,0 +1,68 @@ +// +// detail/gcc_hppa_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_hppa_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_hppa_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_hppa_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_hppa_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/gcc_sync_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/gcc_sync_fenced_block.hpp new file mode 100644 index 0000000..68fdcf7 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/gcc_sync_fenced_block.hpp @@ -0,0 +1,65 @@ +// +// detail/gcc_sync_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_sync_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit gcc_sync_fenced_block(half_or_full_t) + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_sync_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/gcc_x86_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/gcc_x86_fenced_block.hpp new file mode 100644 index 0000000..c21b2ba --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/gcc_x86_fenced_block.hpp @@ -0,0 +1,99 @@ +// +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_x86_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_x86_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_x86_fenced_block(full_t) + { + lbarrier(); + } + + // Destructor. + ~gcc_x86_fenced_block() + { + sbarrier(); + } + +private: + static int barrier() + { + int r = 0, m = 1; + __asm__ __volatile__ ( + "xchgl %0, %1" : + "=r"(r), "=m"(m) : + "0"(1), "m"(m) : + "memory", "cc"); + return r; + } + + static void lbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_lfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("lfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } + + static void sbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_sfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("sfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/global.hpp b/extern/asio-1.18.2/include/asio/detail/global.hpp new file mode 100644 index 0000000..685cf90 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/global.hpp @@ -0,0 +1,52 @@ +// +// detail/global.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_GLOBAL_HPP +#define ASIO_DETAIL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_global.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_global.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_global.hpp" +#elif defined(ASIO_HAS_STD_CALL_ONCE) +# include "asio/detail/std_global.hpp" +#else +# error Only Windows, POSIX and std::call_once are supported! +#endif + +namespace asio { +namespace detail { + +template +inline T& global() +{ +#if !defined(ASIO_HAS_THREADS) + return null_global(); +#elif defined(ASIO_WINDOWS) + return win_global(); +#elif defined(ASIO_HAS_PTHREADS) + return posix_global(); +#elif defined(ASIO_HAS_STD_CALL_ONCE) + return std_global(); +#endif +} + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_GLOBAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_alloc_helpers.hpp b/extern/asio-1.18.2/include/asio/detail/handler_alloc_helpers.hpp new file mode 100644 index 0000000..3c562fc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_alloc_helpers.hpp @@ -0,0 +1,284 @@ +// +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/thread_info_base.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/handler_alloc_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_allocate and asio_handler_deallocate must be made from +// a namespace that does not contain any overloads of these functions. The +// asio_handler_alloc_helpers namespace is defined here for that purpose. +namespace asio_handler_alloc_helpers { + +#if defined(ASIO_NO_DEPRECATED) +template +inline void error_if_hooks_are_defined(Handler& h) +{ + using asio::asio_handler_allocate; + // If you get an error here it is because some of your handlers still + // overload asio_handler_allocate, but this hook is no longer used. + (void)static_cast( + asio_handler_allocate(static_cast(0), + asio::detail::addressof(h))); + + using asio::asio_handler_deallocate; + // If you get an error here it is because some of your handlers still + // overload asio_handler_deallocate, but this hook is no longer used. + (void)static_cast( + asio_handler_deallocate(static_cast(0), + static_cast(0), asio::detail::addressof(h))); +} +#endif // defined(ASIO_NO_DEPRECATED) + +template +inline void* allocate(std::size_t s, Handler& h) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + return ::operator new(s); +#elif defined(ASIO_NO_DEPRECATED) + // The asio_handler_allocate hook is no longer used to obtain memory. + (void)&error_if_hooks_are_defined; + (void)h; +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return asio::detail::thread_info_base::allocate( + asio::detail::thread_context::top_of_thread_call_stack(), s); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return ::operator new(size); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +#else + using asio::asio_handler_allocate; + return asio_handler_allocate(s, asio::detail::addressof(h)); +#endif +} + +template +inline void deallocate(void* p, std::size_t s, Handler& h) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + ::operator delete(p); +#elif defined(ASIO_NO_DEPRECATED) + // The asio_handler_allocate hook is no longer used to obtain memory. + (void)&error_if_hooks_are_defined; + (void)h; +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + asio::detail::thread_info_base::deallocate( + asio::detail::thread_context::top_of_thread_call_stack(), p, s); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)s; + ::operator delete(p); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +#else + using asio::asio_handler_deallocate; + asio_handler_deallocate(p, s, asio::detail::addressof(h)); +#endif +} + +} // namespace asio_handler_alloc_helpers + +namespace asio { +namespace detail { + +template +class hook_allocator +{ +public: + typedef T value_type; + + template + struct rebind + { + typedef hook_allocator other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template + hook_allocator(const hook_allocator& a) + : handler_(a.handler_) + { + } + + T* allocate(std::size_t n) + { + return static_cast( + asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_)); + } + + void deallocate(T* p, std::size_t n) + { + asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_); + } + +//private: + Handler& handler_; +}; + +template +class hook_allocator +{ +public: + typedef void value_type; + + template + struct rebind + { + typedef hook_allocator other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template + hook_allocator(const hook_allocator& a) + : handler_(a.handler_) + { + } + +//private: + Handler& handler_; +}; + +template +struct get_hook_allocator +{ + typedef Allocator type; + + static type get(Handler&, const Allocator& a) + { + return a; + } +}; + +template +struct get_hook_allocator > +{ + typedef hook_allocator type; + + static type get(Handler& handler, const std::allocator&) + { + return type(handler); + } +}; + +} // namespace detail +} // namespace asio + +#define ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + op* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(Handler& handler) \ + { \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + handler, ::asio::get_associated_allocator(handler))); \ + return a.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + *h, ::asio::get_associated_allocator(*h))); \ + a.deallocate(static_cast(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \ + struct ptr \ + { \ + const Alloc* a; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(const Alloc& a) \ + { \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(a)); \ + return a1.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(*a)); \ + a1.deallocate(static_cast(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \ + ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \ + ::asio::detail::thread_info_base::default_tag, op ) \ + /**/ + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_cont_helpers.hpp b/extern/asio-1.18.2/include/asio/detail/handler_cont_helpers.hpp new file mode 100644 index 0000000..5d47465 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_cont_helpers.hpp @@ -0,0 +1,45 @@ +// +// detail/handler_cont_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/handler_continuation_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_is_continuation must be made from a namespace that +// does not contain overloads of this function. This namespace is defined here +// for that purpose. +namespace asio_handler_cont_helpers { + +template +inline bool is_continuation(Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + return false; +#else + using asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + asio::detail::addressof(context)); +#endif +} + +} // namespace asio_handler_cont_helpers + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_invoke_helpers.hpp b/extern/asio-1.18.2/include/asio/detail/handler_invoke_helpers.hpp new file mode 100644 index 0000000..86b8bf2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_invoke_helpers.hpp @@ -0,0 +1,80 @@ +// +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/handler_invoke_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_invoke must be made from a namespace that does not +// contain overloads of this function. The asio_handler_invoke_helpers +// namespace is defined here for that purpose. +namespace asio_handler_invoke_helpers { + +#if defined(ASIO_NO_DEPRECATED) +template +inline void error_if_hook_is_defined(Function& function, Context& context) +{ + using asio::asio_handler_invoke; + // If you get an error here it is because some of your handlers still + // overload asio_handler_invoke, but this hook is no longer used. + (void)static_cast( + asio_handler_invoke(function, asio::detail::addressof(context))); +} +#endif // defined(ASIO_NO_DEPRECATED) + +template +inline void invoke(Function& function, Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#elif defined(ASIO_NO_DEPRECATED) + // The asio_handler_invoke hook is no longer used to invoke the function. + (void)&error_if_hook_is_defined; + (void)context; + function(); +#else + using asio::asio_handler_invoke; + asio_handler_invoke(function, asio::detail::addressof(context)); +#endif +} + +template +inline void invoke(const Function& function, Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#elif defined(ASIO_NO_DEPRECATED) + // The asio_handler_invoke hook is no longer used to invoke the function. + (void)&error_if_hook_is_defined; + (void)context; + Function tmp(function); + tmp(); +#else + using asio::asio_handler_invoke; + asio_handler_invoke(function, asio::detail::addressof(context)); +#endif +} + +} // namespace asio_handler_invoke_helpers + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_tracking.hpp b/extern/asio-1.18.2/include/asio/detail/handler_tracking.hpp new file mode 100644 index 0000000..14195cd --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_tracking.hpp @@ -0,0 +1,264 @@ +// +// detail/handler_tracking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_TRACKING_HPP +#define ASIO_DETAIL_HANDLER_TRACKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { + +class execution_context; + +} // namespace asio + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) +# include ASIO_CUSTOM_HANDLER_TRACKING +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) +# include "asio/error_code.hpp" +# include "asio/detail/cstdint.hpp" +# include "asio/detail/static_mutex.hpp" +# include "asio/detail/tss_ptr.hpp" +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) + +// The user-specified header must define the following macros: +// - ASIO_INHERIT_TRACKED_HANDLER +// - ASIO_ALSO_INHERIT_TRACKED_HANDLER +// - ASIO_HANDLER_TRACKING_INIT +// - ASIO_HANDLER_CREATION(args) +// - ASIO_HANDLER_COMPLETION(args) +// - ASIO_HANDLER_INVOCATION_BEGIN(args) +// - ASIO_HANDLER_INVOCATION_END +// - ASIO_HANDLER_OPERATION(args) +// - ASIO_HANDLER_REACTOR_REGISTRATION(args) +// - ASIO_HANDLER_REACTOR_DEREGISTRATION(args) +// - ASIO_HANDLER_REACTOR_READ_EVENT +// - ASIO_HANDLER_REACTOR_WRITE_EVENT +// - ASIO_HANDLER_REACTOR_ERROR_EVENT +// - ASIO_HANDLER_REACTOR_EVENTS(args) +// - ASIO_HANDLER_REACTOR_OPERATION(args) + +# if !defined(ASIO_ENABLE_HANDLER_TRACKING) +# define ASIO_ENABLE_HANDLER_TRACKING 1 +# endif /// !defined(ASIO_ENABLE_HANDLER_TRACKING) + +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) + +class handler_tracking +{ +public: + class completion; + + // Base class for objects containing tracked handlers. + class tracked_handler + { + private: + // Only the handler_tracking class will have access to the id. + friend class handler_tracking; + friend class completion; + uint64_t id_; + + protected: + // Constructor initialises with no id. + tracked_handler() : id_(0) {} + + // Prevent deletion through this type. + ~tracked_handler() {} + }; + + // Initialise the tracking system. + ASIO_DECL static void init(); + + class location + { + public: + // Constructor adds a location to the stack. + ASIO_DECL explicit location(const char* file, + int line, const char* func); + + // Destructor removes a location from the stack. + ASIO_DECL ~location(); + + private: + // Disallow copying and assignment. + location(const location&) ASIO_DELETED; + location& operator=(const location&) ASIO_DELETED; + + friend class handler_tracking; + const char* file_; + int line_; + const char* func_; + location* next_; + }; + + // Record the creation of a tracked handler. + ASIO_DECL static void creation( + execution_context& context, tracked_handler& h, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + class completion + { + public: + // Constructor records that handler is to be invoked with no arguments. + ASIO_DECL explicit completion(const tracked_handler& h); + + // Destructor records only when an exception is thrown from the handler, or + // if the memory is being freed without the handler having been invoked. + ASIO_DECL ~completion(); + + // Records that handler is to be invoked with no arguments. + ASIO_DECL void invocation_begin(); + + // Records that handler is to be invoked with one arguments. + ASIO_DECL void invocation_begin(const asio::error_code& ec); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, std::size_t bytes_transferred); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, int signal_number); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, const char* arg); + + // Record that handler invocation has ended. + ASIO_DECL void invocation_end(); + + private: + friend class handler_tracking; + uint64_t id_; + bool invoked_; + completion* next_; + }; + + // Record an operation that is not directly associated with a handler. + ASIO_DECL static void operation(execution_context& context, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + // Record that a descriptor has been registered with the reactor. + ASIO_DECL static void reactor_registration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record that a descriptor has been deregistered from the reactor. + ASIO_DECL static void reactor_deregistration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_events(execution_context& context, + uintmax_t registration, unsigned events); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec, std::size_t bytes_transferred); + + // Write a line of output. + ASIO_DECL static void write_line(const char* format, ...); + +private: + struct tracking_state; + ASIO_DECL static tracking_state* get_state(); +}; + +# define ASIO_INHERIT_TRACKED_HANDLER \ + : public asio::detail::handler_tracking::tracked_handler + +# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \ + , public asio::detail::handler_tracking::tracked_handler + +# define ASIO_HANDLER_TRACKING_INIT \ + asio::detail::handler_tracking::init() + +# define ASIO_HANDLER_LOCATION(args) \ + asio::detail::handler_tracking::location tracked_location args + +# define ASIO_HANDLER_CREATION(args) \ + asio::detail::handler_tracking::creation args + +# define ASIO_HANDLER_COMPLETION(args) \ + asio::detail::handler_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) \ + asio::detail::handler_tracking::operation args + +# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \ + asio::detail::handler_tracking::reactor_registration args + +# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ + asio::detail::handler_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) \ + asio::detail::handler_tracking::reactor_events args + +# define ASIO_HANDLER_REACTOR_OPERATION(args) \ + asio::detail::handler_tracking::reactor_operation args + +#else // defined(ASIO_ENABLE_HANDLER_TRACKING) + +# define ASIO_INHERIT_TRACKED_HANDLER +# define ASIO_ALSO_INHERIT_TRACKED_HANDLER +# define ASIO_HANDLER_TRACKING_INIT (void)0 +# define ASIO_HANDLER_LOCATION(loc) (void)0 +# define ASIO_HANDLER_CREATION(args) (void)0 +# define ASIO_HANDLER_COMPLETION(args) (void)0 +# define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 +# define ASIO_HANDLER_INVOCATION_END (void)0 +# define ASIO_HANDLER_OPERATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_READ_EVENT 0 +# define ASIO_HANDLER_REACTOR_WRITE_EVENT 0 +# define ASIO_HANDLER_REACTOR_ERROR_EVENT 0 +# define ASIO_HANDLER_REACTOR_EVENTS(args) (void)0 +# define ASIO_HANDLER_REACTOR_OPERATION(args) (void)0 + +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/handler_tracking.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_HANDLER_TRACKING_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_type_requirements.hpp b/extern/asio-1.18.2/include/asio/detail/handler_type_requirements.hpp new file mode 100644 index 0000000..06de6c9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_type_requirements.hpp @@ -0,0 +1,556 @@ +// +// detail/handler_type_requirements.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP +#define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +// Older versions of gcc have difficulty compiling the sizeof expressions where +// we test the handler type requirements. We'll disable checking of handler type +// requirements for those compilers, but otherwise enable it by default. +#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) +# if !defined(__GNUC__) || (__GNUC__ >= 4) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1 +# endif // !defined(__GNUC__) || (__GNUC__ >= 4) +#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +// With C++0x we can use a combination of enhanced SFINAE and static_assert to +// generate better template error messages. As this technique is not yet widely +// portable, we'll only enable it for tested compilers. +#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# if defined(__clang__) +# if __has_feature(__cxx_static_assert__) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // __has_feature(cxx_static_assert) +# endif // defined(__clang__) +#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) +# include "asio/async_result.hpp" +#endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +namespace asio { +namespace detail { + +#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +# if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template +auto zero_arg_copyable_handler_test(Handler h, void*) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)()), + char(0)); + +template +char (&zero_arg_copyable_handler_test(Handler, ...))[2]; + +template +auto one_arg_handler_test(Handler h, Arg1* a1) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1)), + char(0)); + +template +char (&one_arg_handler_test(Handler h, ...))[2]; + +template +auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, *a2)), + char(0)); + +template +char (&two_arg_handler_test(Handler, ...))[2]; + +template +auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))), + char(0)); + +template +char (&two_arg_move_handler_test(Handler, ...))[2]; + +# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \ + static_assert(expr, msg); + +# else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) + +# endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template T& lvref(); +template T& lvref(T); +template const T& clvref(); +template const T& clvref(T); +#if defined(ASIO_HAS_MOVE) +template T rvref(); +template T rvref(T); +#else // defined(ASIO_HAS_MOVE) +template const T& rvref(); +template const T& rvref(T); +#endif // defined(ASIO_HAS_MOVE) +template char argbyv(T); + +template +struct handler_type_requirements +{ +}; + +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void()) asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::zero_arg_copyable_handler_test( \ + asio::detail::clvref< \ + asio_true_handler_type>(), 0)) == 1, \ + "CompletionHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::clvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()(), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "ReadHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "WriteHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "AcceptHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, socket_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_move_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "MoveAcceptHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::rvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "ConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, endpoint_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, endpoint_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "RangeConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, iter_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "IteratorConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, range_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, range_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "ResolveHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "WaitHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, int)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "SignalHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "HandshakeHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "BufferedHandshakeHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref(), \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "ShutdownHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/handler_work.hpp b/extern/asio-1.18.2/include/asio/detail/handler_work.hpp new file mode 100644 index 0000000..b9cf4f4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/handler_work.hpp @@ -0,0 +1,514 @@ +// +// detail/handler_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HANDLER_WORK_HPP +#define ASIO_DETAIL_HANDLER_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/prefer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class executor; +class io_context; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +class any_io_executor; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +namespace execution { + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template class any_executor; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template class any_executor; + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace execution +namespace detail { + +template +class handler_work_base +{ +public: + explicit handler_work_base(int, int, const Executor& ex) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return true; + } + + template + void dispatch(Function& function, Handler& handler) + { + execution::execute( + asio::prefer(executor_, + execution::blocking.possibly, + execution::allocator((get_associated_allocator)(handler))), + ASIO_MOVE_CAST(Function)(function)); + } + +private: + typedef typename decay< + typename prefer_result::type + >::type executor_type; + + executor_type executor_; +}; + +template +class handler_work_base::value + && (!is_same::value + || !is_same::value) + >::type> +{ +public: + explicit handler_work_base(int, int, const Executor& ex) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const Executor& ex, + const Executor& candidate) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(ex != candidate) + { + if (owns_work_) + executor_.on_work_started(); + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_), + owns_work_(other.owns_work_) + { + if (owns_work_) + executor_.on_work_started(); + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_work_(other.owns_work_) + { + other.owns_work_ = false; + } +#endif // defined(ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (owns_work_) + executor_.on_work_finished(); + } + + bool owns_work() const ASIO_NOEXCEPT + { + return owns_work_; + } + + template + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(ASIO_MOVE_CAST(Function)(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; + bool owns_work_; +}; + +template +class handler_work_base::value + >::type> +{ +public: + explicit handler_work_base(int, int, const Executor&) + { + } + + bool owns_work() const ASIO_NOEXCEPT + { + return false; + } + + template + void dispatch(Function& function, Handler& handler) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + asio_handler_invoke_helpers::invoke(function, handler); + } +}; + +template +class handler_work_base +{ +public: + explicit handler_work_base(int, int, const Executor& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? Executor() : ex) +#else // !defined(ASIO_NO_TYPEID) + : executor_(ex) +#endif // !defined(ASIO_NO_TYPEID) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(const Executor& ex, + const Executor& candidate) ASIO_NOEXCEPT + : executor_(ex != candidate ? ex : Executor()) + { + if (executor_) + executor_.on_work_started(); + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(ex) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + if (executor_) + executor_.on_work_started(); + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (executor_) + executor_.on_work_finished(); + } + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(ASIO_MOVE_CAST(Function)(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; +}; + +template < +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename... SupportableProperties, +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename IoContext, typename PolymorphicExecutor> +class handler_work_base< +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor, +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor, +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + void, IoContext, PolymorphicExecutor> +{ +public: + typedef +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(const executor_type& ex, + const executor_type& candidate) ASIO_NOEXCEPT + : executor_(ex != candidate ? ex : executor_type()) + { + } + + template + handler_work_base(const executor_type& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template + void dispatch(Function& function, Handler&) + { + execution::execute( + asio::prefer(executor_, execution::blocking.possibly), + ASIO_MOVE_CAST(Function)(function)); + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template +class handler_work_base::value + >::type> +{ +public: + typedef Executor executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(const executor_type& ex, + const executor_type& candidate) ASIO_NOEXCEPT + : executor_(ex != candidate ? ex : executor_type()) + { + } + + template + handler_work_base(const executor_type& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template + void dispatch(Function& function, Handler&) + { + execution::execute( + asio::prefer(executor_, execution::blocking.possibly), + ASIO_MOVE_CAST(Function)(function)); + } + +private: + executor_type executor_; +}; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template +class handler_work : + handler_work_base, + handler_work_base::type, IoExecutor> +{ +public: + typedef handler_work_base base1_type; + typedef handler_work_base::type, IoExecutor> base2_type; + + handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT + : base1_type(0, 0, io_ex), + base2_type(asio::get_associated_executor(handler, io_ex), io_ex) + { + } + + template + void complete(Function& function, Handler& handler) + { + if (!base1_type::owns_work() && !base2_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + asio_handler_invoke_helpers::invoke(function, handler); + } + else + { + base2_type::dispatch(function, handler); + } + } +}; + +template +class handler_work< + Handler, IoExecutor, + typename enable_if< + is_same< + typename associated_executor::asio_associated_executor_is_unspecialised, + void + >::value + >::type> : handler_work_base +{ +public: + typedef handler_work_base base1_type; + + handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT + : base1_type(0, 0, io_ex) + { + } + + template + void complete(Function& function, Handler& handler) + { + if (!base1_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + asio_handler_invoke_helpers::invoke(function, handler); + } + else + { + base1_type::dispatch(function, handler); + } + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_WORK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/hash_map.hpp b/extern/asio-1.18.2/include/asio/detail/hash_map.hpp new file mode 100644 index 0000000..78edec8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/hash_map.hpp @@ -0,0 +1,331 @@ +// +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_HASH_MAP_HPP +#define ASIO_DETAIL_HASH_MAP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/socket_types.hpp" +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline std::size_t calculate_hash_value(int i) +{ + return static_cast(i); +} + +inline std::size_t calculate_hash_value(void* p) +{ + return reinterpret_cast(p) + + (reinterpret_cast(p) >> 3); +} + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +inline std::size_t calculate_hash_value(SOCKET s) +{ + return static_cast(s); +} +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Note: assumes K and V are POD types. +template +class hash_map + : private noncopyable +{ +public: + // The type of a value in the map. + typedef std::pair value_type; + + // The type of a non-const iterator over the hash map. + typedef typename std::list::iterator iterator; + + // The type of a const iterator over the hash map. + typedef typename std::list::const_iterator const_iterator; + + // Constructor. + hash_map() + : size_(0), + buckets_(0), + num_buckets_(0) + { + } + + // Destructor. + ~hash_map() + { + delete[] buckets_; + } + + // Get an iterator for the beginning of the map. + iterator begin() + { + return values_.begin(); + } + + // Get an iterator for the beginning of the map. + const_iterator begin() const + { + return values_.begin(); + } + + // Get an iterator for the end of the map. + iterator end() + { + return values_.end(); + } + + // Get an iterator for the end of the map. + const_iterator end() const + { + return values_.end(); + } + + // Check whether the map is empty. + bool empty() const + { + return values_.empty(); + } + + // Find an entry in the map. + iterator find(const K& k) + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Find an entry in the map. + const_iterator find(const K& k) const + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) + return it; + const_iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Insert a new entry into the map. + std::pair insert(const value_type& v) + { + if (size_ + 1 >= num_buckets_) + rehash(hash_size(size_ + 1)); + size_t bucket = calculate_hash_value(v.first) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + { + buckets_[bucket].first = buckets_[bucket].last = + values_insert(values_.end(), v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == v.first) + return std::pair(it, false); + ++it; + } + buckets_[bucket].last = values_insert(end_it, v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + + // Erase an entry from the map. + void erase(iterator it) + { + ASIO_ASSERT(it != values_.end()); + ASIO_ASSERT(num_buckets_ != 0); + + size_t bucket = calculate_hash_value(it->first) % num_buckets_; + bool is_first = (it == buckets_[bucket].first); + bool is_last = (it == buckets_[bucket].last); + if (is_first && is_last) + buckets_[bucket].first = buckets_[bucket].last = values_.end(); + else if (is_first) + ++buckets_[bucket].first; + else if (is_last) + --buckets_[bucket].last; + + values_erase(it); + --size_; + } + + // Erase a key from the map. + void erase(const K& k) + { + iterator it = find(k); + if (it != values_.end()) + erase(it); + } + + // Remove all entries from the map. + void clear() + { + // Clear the values. + values_.clear(); + size_ = 0; + + // Initialise all buckets to empty. + iterator end_it = values_.end(); + for (size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_it; + } + +private: + // Calculate the hash size for the specified number of elements. + static std::size_t hash_size(std::size_t num_elems) + { + static std::size_t sizes[] = + { +#if defined(ASIO_HASH_MAP_BUCKETS) + ASIO_HASH_MAP_BUCKETS +#else // ASIO_HASH_MAP_BUCKETS + 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843 +#endif // ASIO_HASH_MAP_BUCKETS + }; + const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1; + for (std::size_t i = 0; i < nth_size; ++i) + if (num_elems < sizes[i]) + return sizes[i]; + return sizes[nth_size]; + } + + // Re-initialise the hash from the values already contained in the list. + void rehash(std::size_t num_buckets) + { + if (num_buckets == num_buckets_) + return; + ASIO_ASSERT(num_buckets != 0); + + iterator end_iter = values_.end(); + + // Update number of buckets and initialise all buckets to empty. + bucket_type* tmp = new bucket_type[num_buckets]; + delete[] buckets_; + buckets_ = tmp; + num_buckets_ = num_buckets; + for (std::size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_iter; + + // Put all values back into the hash. + iterator iter = values_.begin(); + while (iter != end_iter) + { + std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; + if (buckets_[bucket].last == end_iter) + { + buckets_[bucket].first = buckets_[bucket].last = iter++; + } + else if (++buckets_[bucket].last == iter) + { + ++iter; + } + else + { + values_.splice(buckets_[bucket].last, values_, iter++); + --buckets_[bucket].last; + } + } + } + + // Insert an element into the values list by splicing from the spares list, + // if a spare is available, and otherwise by inserting a new element. + iterator values_insert(iterator it, const value_type& v) + { + if (spares_.empty()) + { + return values_.insert(it, v); + } + else + { + spares_.front() = v; + values_.splice(it, spares_, spares_.begin()); + return --it; + } + } + + // Erase an element from the values list by splicing it to the spares list. + void values_erase(iterator it) + { + *it = value_type(); + spares_.splice(spares_.begin(), values_, it); + } + + // The number of elements in the hash. + std::size_t size_; + + // The list of all values in the hash map. + std::list values_; + + // The list of spare nodes waiting to be recycled. Assumes that POD types only + // are stored in the hash map. + std::list spares_; + + // The type for a bucket in the hash table. + struct bucket_type + { + iterator first; + iterator last; + }; + + // The buckets in the hash. + bucket_type* buckets_; + + // The number of buckets in the hash. + std::size_t num_buckets_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HASH_MAP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/buffer_sequence_adapter.ipp b/extern/asio-1.18.2/include/asio/detail/impl/buffer_sequence_adapter.ipp new file mode 100644 index 0000000..d7c5e35 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/buffer_sequence_adapter.ipp @@ -0,0 +1,118 @@ +// +// detail/impl/buffer_sequence_adapter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP +#define ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include "asio/detail/buffer_sequence_adapter.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_buffer_impl : + public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, + ABI::Windows::Storage::Streams::IBuffer, + Windows::Storage::Streams::IBufferByteAccess> +{ +public: + explicit winrt_buffer_impl(const asio::const_buffer& b) + { + bytes_ = const_cast(static_cast(b.data())); + length_ = b.size(); + capacity_ = b.size(); + } + + explicit winrt_buffer_impl(const asio::mutable_buffer& b) + { + bytes_ = static_cast(b.data()); + length_ = 0; + capacity_ = b.size(); + } + + ~winrt_buffer_impl() + { + } + + STDMETHODIMP Buffer(byte** value) + { + *value = bytes_; + return S_OK; + } + + STDMETHODIMP get_Capacity(UINT32* value) + { + *value = capacity_; + return S_OK; + } + + STDMETHODIMP get_Length(UINT32 *value) + { + *value = length_; + return S_OK; + } + + STDMETHODIMP put_Length(UINT32 value) + { + if (value > capacity_) + return E_INVALIDARG; + length_ = value; + return S_OK; + } + +private: + byte* bytes_; + UINT32 length_; + UINT32 capacity_; +}; + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const asio::mutable_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr insp + = Microsoft::WRL::Make(buffer); + buf = reinterpret_cast(insp.Get()); +} + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const asio::const_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr insp + = Microsoft::WRL::Make(buffer); + Platform::Object^ buf_obj = reinterpret_cast(insp.Get()); + buf = reinterpret_cast(insp.Get()); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/descriptor_ops.ipp b/extern/asio-1.18.2/include/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 0000000..9abf204 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,608 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP +#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/descriptor_ops.hpp" +#include "asio/error.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, asio::error_code& ec) +{ + int result = ::open(path, flags); + get_last_error(ec, result < 0); + return result; +} + +int close(int d, state_type& state, asio::error_code& ec) +{ + int result = 0; + if (d != -1) + { + result = ::close(d); + get_last_error(ec, result < 0); + + if (result != 0 + && (ec == asio::error::would_block + || ec == asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + state &= ~non_blocking; + + result = ::close(d); + get_last_error(ec, result < 0); + } + } + + return result; +} + +bool set_user_non_blocking(int d, state_type& state, + bool value, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return false; + } + +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + + if (result >= 0) + { + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(int d, state_type& state, + bool value, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = asio::error::invalid_argument; + return false; + } + +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + + if (result >= 0) + { + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::readv(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::readv(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_read1(int d, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec.assign(0, ec.category()); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::writev(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_write1(int d, state_type state, const void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + ec.assign(0, ec.category()); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::writev(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_write1(int d, const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + int result = ::ioctl(d, cmd, arg); + get_last_error(ec, result < 0); + + if (result >= 0) + { + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, int cmd, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + int result = ::fcntl(d, cmd); + get_last_error(ec, result < 0); + return result; +} + +int fcntl(int d, int cmd, long arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + int result = ::fcntl(d, cmd, arg); + get_last_error(ec, result < 0); + return result; +} + +int poll_read(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +int poll_write(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +int poll_error(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 0000000..8fac4dd --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,91 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void dev_poll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void dev_poll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void dev_poll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template +std::size_t dev_poll_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void dev_poll_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.ipp b/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 0000000..a60b687 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,446 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/dev_poll_reactor.hpp" +#include "asio/detail/assert.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(asio::execution_context& ctx) + : asio::detail::execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void dev_poll_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + detail::mutex::scoped_lock lock(mutex_); + + if (dev_poll_fd_ != -1) + ::close(dev_poll_fd_); + dev_poll_fd_ = -1; + dev_poll_fd_ = do_dev_poll_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Re-register all descriptors with /dev/poll. The changes will be written + // to the /dev/poll descriptor the next time the reactor is run. + for (int i = 0; i < max_ops; ++i) + { + reactor_op_queue::iterator iter = op_queue_[i].begin(); + reactor_op_queue::iterator end = op_queue_[i].end(); + for (; iter != end; ++iter) + { + ::pollfd& pending_ev = add_pending_event_change(iter->first); + pending_ev.events |= POLLERR | POLLHUP; + switch (i) + { + case read_op: pending_ev.events |= POLLIN; break; + case write_op: pending_ev.events |= POLLOUT; break; + case except_op: pending_ev.events |= POLLPRI; break; + default: break; + } + } + } + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +int dev_poll_reactor::register_internal_descriptor(int op_type, + socket_type descriptor, per_descriptor_data&, reactor_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + switch (op_type) + { + case read_op: ev.events |= POLLIN; break; + case write_op: ev.events |= POLLOUT; break; + case except_op: ev.events |= POLLPRI; break; + default: break; + } + interrupter_.interrupt(); + + return 0; +} + +void dev_poll_reactor::move_descriptor(socket_type, + dev_poll_reactor::per_descriptor_data&, + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_internal_descriptor( + socket_type descriptor, dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. Since this function is only called + // during a fork, we can apply the change immediately. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Destroy all operations associated with the descriptor. + op_queue ops; + asio::error_code ec; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops, ec); +} + +void dev_poll_reactor::cleanup_descriptor_data( + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::run(long usec, op_queue& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) + return; + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + asio::error_code ec = asio::error_code( + errno, asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + // Calculate timeout. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + timeout = get_timeout(timeout); + } + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0, 0, 0 } }; + ::dvpoll dp = { 0, 0, 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout(int msec) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 0000000..cce80e9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,89 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_EPOLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void epoll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void epoll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void epoll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t epoll_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void epoll_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.ipp b/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 0000000..f56c519 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,787 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EPOLL) + +#include +#include +#include "asio/detail/epoll_reactor.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_HAS_TIMERFD) +# include +#endif // defined(ASIO_HAS_TIMERFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + interrupter_(), + epoll_fd_(do_epoll_create()), + timer_fd_(do_timerfd_create()), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } +} + +epoll_reactor::~epoll_reactor() +{ + if (epoll_fd_ != -1) + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void epoll_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + if (epoll_fd_ != -1) + ::close(epoll_fd_); + epoll_fd_ = -1; + epoll_fd_ = do_epoll_create(); + + if (timer_fd_ != -1) + ::close(timer_fd_); + timer_fd_ = -1; + timer_fd_ = do_timerfd_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } + + update_timeout(); + + // Re-register all descriptors with epoll. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + ev.events = state->registered_events_; + ev.data.ptr = state; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev); + if (result != 0) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "epoll re-registration"); + } + } + } +} + +void epoll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + if (errno == EPERM) + { + // This file descriptor type is not supported by epoll. However, if it is + // a regular file then operations on it will not block. We will allow + // this descriptor to be used and fail later if an operation on it would + // otherwise require a trip through the reactor. + descriptor_data->registered_events_ = 0; + return 0; + } + return errno; + } + + return 0; +} + +int epoll_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::move_descriptor(socket_type, + epoll_reactor::per_descriptor_data& target_descriptor_data, + epoll_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (descriptor_data->try_speculative_[op_type]) + { + if (reactor_op::status status = op->perform()) + { + if (status == reactor_op::done_and_exhausted) + if (descriptor_data->registered_events_ != 0) + descriptor_data->try_speculative_[op_type] = false; + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + + if (descriptor_data->registered_events_ == 0) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (op_type == write_op) + { + if ((descriptor_data->registered_events_ & EPOLLOUT) == 0) + { + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_ | EPOLLOUT; + ev.data.ptr = descriptor_data; + if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0) + { + descriptor_data->registered_events_ |= ev.events; + } + else + { + op->ec_ = asio::error_code(errno, + asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + else if (descriptor_data->registered_events_ == 0) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + else + { + if (op_type == write_op) + { + descriptor_data->registered_events_ |= EPOLLOUT; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void epoll_reactor::deregister_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the epoll set when + // it is closed. + } + else if (descriptor_data->registered_events_ != 0) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + } + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void epoll_reactor::run(long usec, op_queue& ops) +{ + // This code relies on the fact that the scheduler queues the reactor task + // behind all descriptor operations generated by this function. This means, + // that by the time we reach this point, any previously returned descriptor + // operations have already been dequeued. Therefore it is now safe for us to + // reuse and return them for the scheduler to queue again. + + // Calculate timeout. Check the timer queues only if timerfd is not in use. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + if (timer_fd_ == -1) + { + mutex::scoped_lock lock(mutex_); + timeout = get_timeout(timeout); + } + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // Ignore. + } +# if defined(ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + // Ignore. + } +# endif // defined(ASIO_HAS_TIMERFD) + else + { + unsigned event_mask = 0; + if ((events[i].events & EPOLLIN) != 0) + event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT; + if ((events[i].events & EPOLLOUT)) + event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT; + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0) + event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT; + ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast(ptr), event_mask)); + } + } +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#if defined(ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + } +#if defined(ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(ASIO_HAS_TIMERFD) + else + { + // The descriptor operation doesn't count as work in and of itself, so we + // don't call work_started() here. This still allows the scheduler to + // stop if the only remaining operations are descriptor operations. + descriptor_state* descriptor_data = static_cast(ptr); + if (!ops.is_enqueued(descriptor_data)) + { + descriptor_data->set_ready_events(events[i].events); + ops.push(descriptor_data); + } + else + { + descriptor_data->add_ready_events(events[i].events); + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::interrupt() +{ + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); +} + +int epoll_reactor::do_epoll_create() +{ +#if defined(EPOLL_CLOEXEC) + int fd = epoll_create1(EPOLL_CLOEXEC); +#else // defined(EPOLL_CLOEXEC) + int fd = -1; + errno = EINVAL; +#endif // defined(EPOLL_CLOEXEC) + + if (fd == -1 && (errno == EINVAL || errno == ENOSYS)) + { + fd = epoll_create(epoll_size); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "epoll"); + } + + return fd; +} + +int epoll_reactor::do_timerfd_create() +{ +#if defined(ASIO_HAS_TIMERFD) +# if defined(TFD_CLOEXEC) + int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +# else // defined(TFD_CLOEXEC) + int fd = -1; + errno = EINVAL; +# endif // defined(TFD_CLOEXEC) + + if (fd == -1 && errno == EINVAL) + { + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + return fd; +#else // defined(ASIO_HAS_TIMERFD) + return -1; +#endif // defined(ASIO_HAS_TIMERFD) +} + +epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(ASIO_HAS_TIMERFD) + interrupt(); +} + +int epoll_reactor::get_timeout(int msec) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +#if defined(ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; +} +#endif // defined(ASIO_HAS_TIMERFD) + +struct epoll_reactor::perform_io_cleanup_on_block_exit +{ + explicit perform_io_cleanup_on_block_exit(epoll_reactor* r) + : reactor_(r), first_op_(0) + { + } + + ~perform_io_cleanup_on_block_exit() + { + if (first_op_) + { + // Post the remaining completed operations for invocation. + if (!ops_.empty()) + reactor_->scheduler_.post_deferred_completions(ops_); + + // A user-initiated operation has completed, but there's no need to + // explicitly call work_finished() here. Instead, we'll take advantage of + // the fact that the scheduler will call work_finished() once we return. + } + else + { + // No user-initiated operations have completed, so we need to compensate + // for the work_finished() call that the scheduler will make once this + // operation returns. + reactor_->scheduler_.compensating_work_started(); + } + } + + epoll_reactor* reactor_; + op_queue ops_; + operation* first_op_; +}; + +epoll_reactor::descriptor_state::descriptor_state(bool locking) + : operation(&epoll_reactor::descriptor_state::do_complete), + mutex_(locking) +{ +} + +operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) +{ + mutex_.lock(); + perform_io_cleanup_on_block_exit io_cleanup(reactor_); + mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + try_speculative_[j] = true; + while (reactor_op* op = op_queue_[j].front()) + { + if (reactor_op::status status = op->perform()) + { + op_queue_[j].pop(); + io_cleanup.ops_.push(op); + if (status == reactor_op::done_and_exhausted) + { + try_speculative_[j] = false; + break; + } + } + else + break; + } + } + } + + // The first operation will be returned for completion now. The others will + // be posted for later by the io_cleanup object's destructor. + io_cleanup.first_op_ = io_cleanup.ops_.front(); + io_cleanup.ops_.pop(); + return io_cleanup.first_op_; +} + +void epoll_reactor::descriptor_state::do_complete( + void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) +{ + if (owner) + { + descriptor_state* descriptor_data = static_cast(base); + uint32_t events = static_cast(bytes_transferred); + if (operation* op = descriptor_data->perform_io(events)) + { + op->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/eventfd_select_interrupter.ipp b/extern/asio-1.18.2/include/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 0000000..8ed61f8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,171 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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 ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EVENTFD) + +#include +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) +#include "asio/detail/cstdint.hpp" +#include "asio/detail/eventfd_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ + open_descriptors(); +} + +void eventfd_select_interrupter::open_descriptors() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) +# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + write_descriptor_ = read_descriptor_ = + ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); +# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + errno = EINVAL; + write_descriptor_ = read_descriptor_ = -1; +# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + if (read_descriptor_ == -1 && errno == EINVAL) + { + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } + } +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) + + if (read_descriptor_ == -1) + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + close_descriptors(); +} + +void eventfd_select_interrupter::close_descriptors() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + return true; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read == sizeof(data)) + continue; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (errno == EINTR) + continue; + if (errno == EWOULDBLOCK) + return true; + if (errno == EAGAIN) + return true; + return false; + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EVENTFD) + +#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/handler_tracking.ipp b/extern/asio-1.18.2/include/asio/detail/impl/handler_tracking.ipp new file mode 100644 index 0000000..79a87df --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/handler_tracking.ipp @@ -0,0 +1,396 @@ +// +// detail/impl/handler_tracking.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP +#define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) + +// The handler tracking implementation is provided by the user-specified header. + +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include +#include +#include "asio/detail/handler_tracking.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/time_traits.hpp" +#elif defined(ASIO_HAS_CHRONO) +# include "asio/detail/chrono.hpp" +# include "asio/detail/chrono_time_traits.hpp" +# include "asio/wait_traits.hpp" +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/socket_types.hpp" +#elif !defined(ASIO_WINDOWS) +# include +#endif // !defined(ASIO_WINDOWS) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct handler_tracking_timestamp +{ + uint64_t seconds; + uint64_t microseconds; + + handler_tracking_timestamp() + { +#if defined(ASIO_HAS_BOOST_DATE_TIME) + boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + boost::posix_time::time_duration now = + boost::posix_time::microsec_clock::universal_time() - epoch; +#elif defined(ASIO_HAS_CHRONO) + typedef chrono_time_traits > traits_helper; + traits_helper::posix_time_duration now( + chrono::system_clock::now().time_since_epoch()); +#endif + seconds = static_cast(now.total_seconds()); + microseconds = static_cast(now.total_microseconds() % 1000000); + } +}; + +struct handler_tracking::tracking_state +{ + static_mutex mutex_; + uint64_t next_id_; + tss_ptr* current_completion_; + tss_ptr* current_location_; +}; + +handler_tracking::tracking_state* handler_tracking::get_state() +{ + static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0, 0 }; + return &state; +} + +void handler_tracking::init() +{ + static tracking_state* state = get_state(); + + state->mutex_.init(); + + static_mutex::scoped_lock lock(state->mutex_); + if (state->current_completion_ == 0) + state->current_completion_ = new tss_ptr; + if (state->current_location_ == 0) + state->current_location_ = new tss_ptr; +} + +handler_tracking::location::location( + const char* file, int line, const char* func) + : file_(file), + line_(line), + func_(func), + next_(*get_state()->current_location_) +{ + if (file_) + *get_state()->current_location_ = this; +} + +handler_tracking::location::~location() +{ + if (file_) + *get_state()->current_location_ = next_; +} + +void handler_tracking::creation(execution_context&, + handler_tracking::tracked_handler& h, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + static_mutex::scoped_lock lock(state->mutex_); + h.id_ = state->next_id_++; + lock.unlock(); + + handler_tracking_timestamp timestamp; + + uint64_t current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + for (location* current_location = *state->current_location_; + current_location; current_location = current_location->next_) + { + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, + current_location == *state->current_location_ ? "in " : "called from ", + current_location->func_ ? "'" : "", + current_location->func_ ? current_location->func_ : "", + current_location->func_ ? "' " : "", + current_location->file_, current_location->line_); + } + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, object_type, object, op_name); +} + +handler_tracking::completion::completion( + const handler_tracking::tracked_handler& h) + : id_(h.id_), + invoked_(false), + next_(*get_state()->current_completion_) +{ + *get_state()->current_completion_ = this; +} + +handler_tracking::completion::~completion() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%c%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%c%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + invoked_ ? '!' : '~', id_); + } + + *get_state()->current_completion_ = next_; +} + +void handler_tracking::completion::invocation_begin() +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value()); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), + static_cast(bytes_transferred)); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, int signal_number) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), signal_number); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, const char* arg) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), arg); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_end() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|<%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|<%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + id_ = 0; + } +} + +void handler_tracking::operation(execution_context&, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + handler_tracking_timestamp timestamp; + + unsigned long long current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, object_type, object, op_name); +} + +void handler_tracking::reactor_registration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_deregistration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_events(execution_context& /*context*/, + uintmax_t /*native_handle*/, unsigned /*events*/) +{ +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value()); +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value(), + static_cast(bytes_transferred)); +} + +void handler_tracking::write_line(const char* format, ...) +{ + using namespace std; // For sprintf (or equivalent). + + va_list args; + va_start(args, format); + + char line[256] = ""; +#if defined(ASIO_HAS_SECURE_RTL) + int length = vsprintf_s(line, sizeof(line), format, args); +#else // defined(ASIO_HAS_SECURE_RTL) + int length = vsprintf(line, format, args); +#endif // defined(ASIO_HAS_SECURE_RTL) + + va_end(args); + +#if defined(ASIO_WINDOWS_RUNTIME) + wchar_t wline[256] = L""; + mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length); + ::OutputDebugStringW(wline); +#elif defined(ASIO_WINDOWS) + HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE); + DWORD bytes_written = 0; + ::WriteFile(stderr_handle, line, length, &bytes_written, 0); +#else // defined(ASIO_WINDOWS) + ::write(STDERR_FILENO, line, length); +#endif // defined(ASIO_WINDOWS) +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 0000000..67079f0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,93 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void kqueue_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void kqueue_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void kqueue_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupt(); +} + +template +std::size_t kqueue_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void kqueue_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.ipp b/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 0000000..8a5d26c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,570 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/kqueue_reactor.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#if defined(__NetBSD__) +# include +#endif + +#include "asio/detail/push_options.hpp" + +#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500 +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, \ + reinterpret_cast(static_cast(udata))) +#else +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, udata) +#endif + +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + struct kevent events[1]; + ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + asio::error_code error(errno, + asio::error::get_system_category()); + asio::detail::throw_error(error); + } +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void kqueue_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + // The kqueue descriptor is automatically closed in the child. + kqueue_fd_ = -1; + kqueue_fd_ = do_kqueue_create(); + + interrupter_.recreate(); + + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue interrupter registration"); + } + + // Re-register all descriptors with kqueue. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + if (state->num_kevents_ > 0) + { + ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_, + EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state); + ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_, + EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state); + if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue re-registration"); + } + } + } + } +} + +void kqueue_reactor::init_task() +{ + scheduler_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 0; + descriptor_data->shutdown_ = false; + + return 0; +} + +int kqueue_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 1; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + + struct kevent events[1]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + return errno; + + return 0; +} + +void kqueue_reactor::move_descriptor(socket_type, + kqueue_reactor::per_descriptor_data& target_descriptor_data, + kqueue_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + static const int num_kevents[max_ops] = { 1, 2, 1 }; + + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1) + { + descriptor_data->num_kevents_ = num_kevents[op_type]; + } + else + { + op->ec_ = asio::error_code(errno, + asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + else + { + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + descriptor_data->num_kevents_ = num_kevents[op_type]; + + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void kqueue_reactor::deregister_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the kqueue when it + // is closed. + } + else + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void kqueue_reactor::run(long usec, op_queue& ops) +{ + mutex::scoped_lock lock(mutex_); + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast(events[i].udata); + if (ptr != &interrupter_) + { + unsigned event_mask = 0; + switch (events[i].filter) + { + case EVFILT_READ: + event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT; + break; + case EVFILT_WRITE: + event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT; + break; + } + if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0) + event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT; + ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast(ptr), event_mask)); + } + } +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast(events[i].udata); + if (ptr == &interrupter_) + { + interrupter_.reset(); + } + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (events[i].filter == EVFILT_WRITE + && descriptor_data->num_kevents_ == 2 + && descriptor_data->op_queue_[write_op].empty()) + { + // Some descriptor types, like serial ports, don't seem to support + // EV_CLEAR with EVFILT_WRITE. Since we have no pending write + // operations we'll remove the EVFILT_WRITE registration here so that + // we don't end up in a tight spin. + struct kevent delete_events[1]; + ASIO_KQUEUE_EV_SET(&delete_events[0], + descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0); + descriptor_data->num_kevents_ = 1; + } + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. +#if defined(__NetBSD__) + static const unsigned int filter[max_ops] = +#else + static const int filter[max_ops] = +#endif + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = asio::error_code( + static_cast(events[i].data), + asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(long usec, timespec& ts) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio + +#undef ASIO_KQUEUE_EV_SET + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/null_event.ipp b/extern/asio-1.18.2/include/asio/detail/impl/null_event.ipp new file mode 100644 index 0000000..7b8f968 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/null_event.ipp @@ -0,0 +1,74 @@ +// +// detail/impl/null_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_NULL_EVENT_IPP +#define ASIO_DETAIL_IMPL_NULL_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/socket_types.hpp" +#else +# include +# if defined(__hpux) +# include +# endif +# if !defined(__hpux) || defined(__SELECT) +# include +# endif +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void null_event::do_wait() +{ +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)()); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(INFINITE); +#else + ::pause(); +#endif +} + +void null_event::do_wait_for_usec(long usec) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for(std::chrono::microseconds(usec)); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(usec / 1000); +#elif defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pselect(0, 0, 0, 0, &ts, 0); +#else + timeval tv; + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + ::select(0, 0, 0, 0, &tv); +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_NULL_EVENT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/pipe_select_interrupter.ipp b/extern/asio-1.18.2/include/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 0000000..31c1b5c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,129 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) +#if !defined(ASIO_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) + +#include +#include +#include +#include +#include "asio/detail/pipe_select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + open_descriptors(); +} + +void pipe_select_interrupter::open_descriptors() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + close_descriptors(); +} + +void pipe_select_interrupter::close_descriptors() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + signed_size_type result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read == sizeof(data)) + continue; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (errno == EINTR) + continue; + if (errno == EWOULDBLOCK || errno == EAGAIN) + return true; + return false; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(ASIO_WINDOWS) +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/posix_event.ipp b/extern/asio-1.18.2/include/asio/detail/impl/posix_event.ipp new file mode 100644 index 0000000..a823d8f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/posix_event.ipp @@ -0,0 +1,63 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_POSIX_EVENT_IPP +#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_event.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_event::posix_event() + : state_(0) +{ +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + int error = ::pthread_cond_init(&cond_, 0); +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + ::pthread_condattr_t attr; + int error = ::pthread_condattr_init(&attr); + if (error == 0) + { + error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (error == 0) + error = ::pthread_cond_init(&cond_, &attr); + ::pthread_condattr_destroy(&attr); + } +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/posix_mutex.ipp b/extern/asio-1.18.2/include/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 0000000..c553ab4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP +#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_mutex.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/posix_thread.ipp b/extern/asio-1.18.2/include/asio/detail/impl/posix_thread.ipp new file mode 100644 index 0000000..94373ee --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,84 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_POSIX_THREAD_IPP +#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_thread.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +std::size_t posix_thread::hardware_concurrency() +{ +#if defined(_SC_NPROCESSORS_ONLN) + long result = sysconf(_SC_NPROCESSORS_ONLN); + if (result > 0) + return result; +#endif // defined(_SC_NPROCESSORS_ONLN) + return 0; +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } +} + +void* asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/posix_tss_ptr.ipp b/extern/asio-1.18.2/include/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 0000000..6a368e0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_tss_ptr.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/reactive_descriptor_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 0000000..9caf068 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,223 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/error.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + execution_context& context) + : execution_context_service_base(context), + reactor_(asio::use_service(context)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::move_construct( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service::implementation_type& other_impl) + ASIO_NOEXCEPT +{ + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::move_assign( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service& other_service, + reactive_descriptor_service::implementation_type& other_impl) +{ + destroy(impl); + + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +asio::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_handle_type& native_descriptor, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = descriptor_ops::possible_dup; + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + descriptor_ops::close(impl.descriptor_, impl.state_, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour.) + construct(impl); + + return ec; +} + +reactive_descriptor_service::native_handle_type +reactive_descriptor_service::release( + reactive_descriptor_service::implementation_type& impl) +{ + native_handle_type descriptor = impl.descriptor_; + + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "release")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + construct(impl); + } + + return descriptor; +} + +asio::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "cancel")); + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/reactive_serial_port_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 0000000..23515a9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,149 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include "asio/detail/reactive_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + execution_context& context) + : execution_context_service_base(context), + descriptor_service_(context) +{ +} + +void reactive_serial_port_service::shutdown() +{ + descriptor_service_.shutdown(); +} + +asio::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + s = ::tcgetattr(fd, &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s >= 0) + { +#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + s = ::tcsetattr(fd, TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); + } + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +asio::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + termios ios; + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) + return ec; + + if (store(option, ios, ec)) + return ec; + + s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); + return ec; +} + +asio::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + termios ios; + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/reactive_socket_service_base.ipp b/extern/asio-1.18.2/include/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 0000000..afda16f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,300 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/reactive_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + execution_context& context) + : reactor_(use_service(context)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::base_shutdown() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::base_move_construct( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base::base_implementation_type& other_impl) + ASIO_NOEXCEPT +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::base_move_assign( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base& other_service, + reactive_socket_service_base::base_implementation_type& other_impl) +{ + destroy(impl); + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +asio::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour. The + // known exception is when Windows's closesocket() function fails with + // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close(). + construct(impl); + + return ec; +} + +socket_type reactive_socket_service_base::release( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "release")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = asio::error_code(); + return sock; +} + +asio::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "cancel")); + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_handle_type& native_socket, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.state_ |= socket_ops::possible_dup; + ec = asio::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, is_continuation, true, false); + else + { + op->ec_ = asio::error::already_open; + reactor_.post_immediate_completion(op, is_continuation); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + reactor_.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, is_continuation, false); + return; + } + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/resolver_service_base.ipp b/extern/asio-1.18.2/include/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 0000000..bd1b0bc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,158 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base::work_scheduler_runner +{ +public: + work_scheduler_runner(scheduler_impl& work_scheduler) + : work_scheduler_(work_scheduler) + { + } + + void operator()() + { + asio::error_code ec; + work_scheduler_.run(ec); + } + +private: + scheduler_impl& work_scheduler_; +}; + +resolver_service_base::resolver_service_base(execution_context& context) + : scheduler_(asio::use_service(context)), + work_scheduler_(new scheduler_impl(context, -1, false)), + work_thread_(0) +{ + work_scheduler_->work_started(); +} + +resolver_service_base::~resolver_service_base() +{ + base_shutdown(); +} + +void resolver_service_base::base_shutdown() +{ + if (work_scheduler_.get()) + { + work_scheduler_->work_finished(); + work_scheduler_->stop(); + if (work_thread_.get()) + { + work_thread_->join(); + work_thread_.reset(); + } + work_scheduler_.reset(); + } +} + +void resolver_service_base::base_notify_fork( + execution_context::fork_event fork_ev) +{ + if (work_thread_.get()) + { + if (fork_ev == execution_context::fork_prepare) + { + work_scheduler_->stop(); + work_thread_->join(); + work_thread_.reset(); + } + } + else if (fork_ev != execution_context::fork_prepare) + { + work_scheduler_->restart(); + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type& impl) +{ + ASIO_HANDLER_OPERATION((scheduler_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(); +} + +void resolver_service_base::move_construct(implementation_type& impl, + implementation_type& other_impl) +{ + impl = ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::move_assign(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) +{ + destroy(impl); + impl = ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + ASIO_HANDLER_OPERATION((scheduler_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(resolve_op* op) +{ + if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + scheduler_.concurrency_hint())) + { + start_work_thread(); + scheduler_.work_started(); + work_scheduler_->post_immediate_completion(op, false); + } + else + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, false); + } +} + +void resolver_service_base::start_work_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_.get()) + { + work_thread_.reset(new asio::detail::thread( + work_scheduler_runner(*work_scheduler_))); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/scheduler.ipp b/extern/asio-1.18.2/include/asio/detail/impl/scheduler.ipp new file mode 100644 index 0000000..0734fc8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/scheduler.ipp @@ -0,0 +1,659 @@ +// +// detail/impl/scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SCHEDULER_IPP +#define ASIO_DETAIL_IMPL_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/scheduler_thread_info.hpp" +#include "asio/detail/signal_blocker.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler::thread_function +{ +public: + explicit thread_function(scheduler* s) + : this_(s) + { + } + + void operator()() + { + asio::error_code ec; + this_->run(ec); + } + +private: + scheduler* this_; +}; + +struct scheduler::task_cleanup +{ + ~task_cleanup() + { + if (this_thread_->private_outstanding_work > 0) + { + asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work); + } + this_thread_->private_outstanding_work = 0; + + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + scheduler_->task_interrupted_ = true; + scheduler_->op_queue_.push(this_thread_->private_op_queue); + scheduler_->op_queue_.push(&scheduler_->task_operation_); + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +struct scheduler::work_cleanup +{ + ~work_cleanup() + { + if (this_thread_->private_outstanding_work > 1) + { + asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work - 1); + } + else if (this_thread_->private_outstanding_work < 1) + { + scheduler_->work_finished(); + } + this_thread_->private_outstanding_work = 0; + +#if defined(ASIO_HAS_THREADS) + if (!this_thread_->private_op_queue.empty()) + { + lock_->lock(); + scheduler_->op_queue_.push(this_thread_->private_op_queue); + } +#endif // defined(ASIO_HAS_THREADS) + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +scheduler::scheduler(asio::execution_context& ctx, + int concurrency_hint, bool own_thread) + : asio::detail::execution_context_service_base(ctx), + one_thread_(concurrency_hint == 1 + || !ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint) + || !ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, concurrency_hint)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint)), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + concurrency_hint_(concurrency_hint), + thread_(0) +{ + ASIO_HANDLER_TRACKING_INIT; + + if (own_thread) + { + ++outstanding_work_; + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread(thread_function(this)); + } +} + +scheduler::~scheduler() +{ + if (thread_) + { + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_all_threads(lock); + lock.unlock(); + thread_->join(); + delete thread_; + } +} + +void scheduler::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + if (thread_) + stop_all_threads(lock); + lock.unlock(); + + // Join thread to ensure task operation is returned to queue. + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void scheduler::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->context()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t scheduler::run(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_run_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t scheduler::run_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_run_one(lock, this_thread, ec); +} + +std::size_t scheduler::wait_one(long usec, asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_wait_one(lock, this_thread, usec, ec); +} + +std::size_t scheduler::poll(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(ASIO_HAS_THREADS) + + std::size_t n = 0; + for (; do_poll_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t scheduler::poll_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(ASIO_HAS_THREADS) + + return do_poll_one(lock, this_thread, ec); +} + +void scheduler::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +bool scheduler::stopped() const +{ + mutex::scoped_lock lock(mutex_); + return stopped_; +} + +void scheduler::restart() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void scheduler::compensating_work_started() +{ + thread_info_base* this_thread = thread_call_stack::contains(this); + ++static_cast(this_thread)->private_outstanding_work; +} + +bool scheduler::can_dispatch() +{ + return thread_call_stack::contains(this) != 0; +} + +void scheduler::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + +void scheduler::post_immediate_completion( + scheduler::operation* op, bool is_continuation) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_ || is_continuation) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + ++static_cast(this_thread)->private_outstanding_work; + static_cast(this_thread)->private_op_queue.push(op); + return; + } + } +#else // defined(ASIO_HAS_THREADS) + (void)is_continuation; +#endif // defined(ASIO_HAS_THREADS) + + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_immediate_completions(std::size_t n, + op_queue& ops, bool is_continuation) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_ || is_continuation) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast(this_thread)->private_outstanding_work + += static_cast(n); + static_cast(this_thread)->private_op_queue.push(ops); + return; + } + } +#else // defined(ASIO_HAS_THREADS) + (void)is_continuation; +#endif // defined(ASIO_HAS_THREADS) + + increment(outstanding_work_, static_cast(n)); + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completion(scheduler::operation* op) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast(this_thread)->private_op_queue.push(op); + return; + } + } +#endif // defined(ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completions( + op_queue& ops) +{ + if (!ops.empty()) + { +#if defined(ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast(this_thread)->private_op_queue.push(ops); + return; + } + } +#endif // defined(ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +void scheduler::do_dispatch( + scheduler::operation* op) +{ + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::abandon_operations( + op_queue& ops) +{ + op_queue ops2; + ops2.push(ops); +} + +std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const asio::error_code& ec) +{ + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue); + } + else + { + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); + + return 1; + } + } + else + { + wakeup_event_.clear(lock); + wakeup_event_.wait(lock); + } + } + + return 0; +} + +std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, long usec, + const asio::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == 0) + { + wakeup_event_.clear(lock); + wakeup_event_.wait_for_usec(lock, usec); + usec = 0; // Wait at most once. + o = op_queue_.front(); + } + + if (o == &task_operation_) + { + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + { + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + if (!one_thread_) + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); + + return 1; +} + +std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const asio::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == &task_operation_) + { + op_queue_.pop(); + lock.unlock(); + + { + task_cleanup c = { this, &lock, &this_thread }; + (void)c; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(0, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); + + return 1; +} + +void scheduler::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + wakeup_event_.signal_all(lock); + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +void scheduler::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wakeup_event_.maybe_unlock_and_signal_one(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SCHEDULER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.hpp new file mode 100644 index 0000000..f37769f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,100 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void select_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void select_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void select_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template +std::size_t select_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void select_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.ipp b/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.ipp new file mode 100644 index 0000000..4c855e2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,338 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include "asio/detail/fd_set_adapter.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) +class select_reactor::thread_function +{ +public: + explicit thread_function(select_reactor* r) + : this_(r) + { + } + + void operator()() + { + this_->run_thread(); + } + +private: + select_reactor* this_; +}; +#endif // defined(ASIO_HAS_IOCP) + +select_reactor::select_reactor(asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(), + interrupter_(), +#if defined(ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(ASIO_HAS_IOCP) + shutdown_(false) +{ +#if defined(ASIO_HAS_IOCP) + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread(thread_function(this)); +#endif // defined(ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown(); +} + +void select_reactor::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(ASIO_HAS_IOCP) + stop_thread_ = true; + if (thread_) + interrupter_.interrupt(); +#endif // defined(ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(ASIO_HAS_IOCP) + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(ASIO_HAS_IOCP) + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void select_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + interrupter_.recreate(); +} + +void select_reactor::init_task() +{ + scheduler_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +int select_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + interrupter_.interrupt(); + + return 0; +} + +void select_reactor::move_descriptor(socket_type, + select_reactor::per_descriptor_data&, + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + interrupter_.interrupt(); +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::deregister_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::deregister_internal_descriptor( + socket_type descriptor, select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops); +} + +void select_reactor::cleanup_descriptor_data( + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::run(long usec, op_queue& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(ASIO_HAS_IOCP) + + // Set up the descriptor sets. + for (int i = 0; i < max_select_ops; ++i) + fd_sets_[i].reset(); + fd_sets_[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + fd_sets_[i].set(op_queue_[i], ops); + if (fd_sets_[i].max_descriptor() > max_fd) + max_fd = fd_sets_[i].max_descriptor(); + } + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + fd_sets_[write_op].set(op_queue_[connect_op], ops); + if (fd_sets_[write_op].max_descriptor() > max_fd) + max_fd = fd_sets_[write_op].max_descriptor(); + fd_sets_[except_op].set(op_queue_[connect_op], ops); + if (fd_sets_[except_op].max_descriptor() > max_fd) + max_fd = fd_sets_[except_op].max_descriptor(); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!usec && !have_work_to_do) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + asio::error_code ec; + int retval = socket_ops::select(static_cast(max_fd + 1), + fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor())) + { + if (!interrupter_.reset()) + { + lock.lock(); + interrupter_.recreate(); + } + --retval; + } + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + fd_sets_[except_op].perform(op_queue_[connect_op], ops); + fd_sets_[write_op].perform(op_queue_[connect_op], ops); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + fd_sets_[i].perform(op_queue_[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + scheduler_.post_deferred_completions(ops); + lock.lock(); + } +} +#endif // defined(ASIO_HAS_IOCP) + +void select_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(long usec, timeval& tv) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE)) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/service_registry.hpp b/extern/asio-1.18.2/include/asio/detail/impl/service_registry.hpp new file mode 100644 index 0000000..8b9566e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/service_registry.hpp @@ -0,0 +1,94 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +Service& service_registry::use_service() +{ + execution_context::service::key key; + init_key(key, 0); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory, &owner_)); +} + +template +Service& service_registry::use_service(io_context& owner) +{ + execution_context::service::key key; + init_key(key, 0); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory, &owner)); +} + +template +void service_registry::add_service(Service* new_service) +{ + execution_context::service::key key; + init_key(key, 0); + return do_add_service(key, new_service); +} + +template +bool service_registry::has_service() const +{ + execution_context::service::key key; + init_key(key, 0); + return do_has_service(key); +} + +template +inline void service_registry::init_key( + execution_context::service::key& key, ...) +{ + init_key_from_id(key, Service::id); +} + +#if !defined(ASIO_NO_TYPEID) +template +void service_registry::init_key(execution_context::service::key& key, + typename enable_if< + is_base_of::value>::type*) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} + +template +void service_registry::init_key_from_id(execution_context::service::key& key, + const service_id& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} +#endif // !defined(ASIO_NO_TYPEID) + +template +execution_context::service* service_registry::create(void* owner) +{ + return new Service(*static_cast(owner)); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/service_registry.ipp b/extern/asio-1.18.2/include/asio/detail/impl/service_registry.ipp new file mode 100644 index 0000000..363a56f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/service_registry.ipp @@ -0,0 +1,197 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/service_registry.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +service_registry::service_registry(execution_context& owner) + : owner_(owner), + first_service_(0) +{ +} + +service_registry::~service_registry() +{ +} + +void service_registry::shutdown_services() +{ + execution_context::service* service = first_service_; + while (service) + { + service->shutdown(); + service = service->next_; + } +} + +void service_registry::destroy_services() +{ + while (first_service_) + { + execution_context::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::notify_fork(execution_context::fork_event fork_ev) +{ + // Make a copy of all of the services while holding the lock. We don't want + // to hold the lock while calling into each service, as it may try to call + // back into this class. + std::vector services; + { + asio::detail::mutex::scoped_lock lock(mutex_); + execution_context::service* service = first_service_; + while (service) + { + services.push_back(service); + service = service->next_; + } + } + + // If processing the fork_prepare event, we want to go in reverse order of + // service registration, which happens to be the existing order of the + // services in the vector. For the other events we want to go in the other + // direction. + std::size_t num_services = services.size(); + if (fork_ev == execution_context::fork_prepare) + for (std::size_t i = 0; i < num_services; ++i) + services[i]->notify_fork(fork_ev); + else + for (std::size_t i = num_services; i > 0; --i) + services[i - 1]->notify_fork(fork_ev); +} + +void service_registry::init_key_from_id(execution_context::service::key& key, + const execution_context::id& id) +{ + key.type_info_ = 0; + key.id_ = &id; +} + +bool service_registry::keys_match( + const execution_context::service::key& key1, + const execution_context::service::key& key2) +{ + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; +} + +void service_registry::destroy(execution_context::service* service) +{ + delete service; +} + +execution_context::service* service_registry::do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + auto_service_ptr new_service = { factory(owner) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service) +{ + if (&owner_ != &new_service->context()) + asio::detail::throw_exception(invalid_service_owner()); + + asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + asio::detail::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const execution_context::service::key& key) const +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/signal_set_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/signal_set_service.ipp new file mode 100644 index 0000000..b657d0e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/signal_set_service.ipp @@ -0,0 +1,668 @@ +// +// detail/impl/signal_set_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP +#define ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include +#include +#include "asio/detail/reactor.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/signal_set_service.hpp" +#include "asio/detail/static_mutex.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct signal_state +{ + // Mutex used for protecting global state. + static_mutex mutex_; + + // The read end of the pipe used for signal notifications. + int read_descriptor_; + + // The write end of the pipe used for signal notifications. + int write_descriptor_; + + // Whether the signal state has been prepared for a fork. + bool fork_prepared_; + + // The head of a linked list of all signal_set_service instances. + class signal_set_service* service_list_; + + // A count of the number of objects that are registered for each signal. + std::size_t registration_count_[max_signal_number]; +}; + +signal_state* get_signal_state() +{ + static signal_state state = { + ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } }; + return &state; +} + +void asio_signal_handler(int signal_number) +{ +#if defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) + signal_set_service::deliver_signal(signal_number); +#else // defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + int saved_errno = errno; + signal_state* state = get_signal_state(); + signed_size_type result = ::write(state->write_descriptor_, + &signal_number, sizeof(signal_number)); + (void)result; + errno = saved_errno; +#endif // defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + +#if defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION) + ::signal(signal_number, asio_signal_handler); +#endif // defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION) +} + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +class signal_set_service::pipe_read_op : public reactor_op +{ +public: + pipe_read_op() + : reactor_op(asio::error_code(), + &pipe_read_op::do_perform, pipe_read_op::do_complete) + { + } + + static status do_perform(reactor_op*) + { + signal_state* state = get_signal_state(); + + int fd = state->read_descriptor_; + int signal_number = 0; + while (::read(fd, &signal_number, sizeof(int)) == sizeof(int)) + if (signal_number >= 0 && signal_number < max_signal_number) + signal_set_service::deliver_signal(signal_number); + + return not_done; + } + + static void do_complete(void* /*owner*/, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + pipe_read_op* o(static_cast(base)); + delete o; + } +}; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +signal_set_service::signal_set_service(execution_context& context) + : execution_context_service_base(context), + scheduler_(asio::use_service(context)), +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_(asio::use_service(context)), +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + next_(0), + prev_(0) +{ + get_signal_state()->mutex_.init(); + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_.init_task(); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + for (int i = 0; i < max_signal_number; ++i) + registrations_[i] = 0; + + add_service(this); +} + +signal_set_service::~signal_set_service() +{ + remove_service(this); +} + +void signal_set_service::shutdown() +{ + remove_service(this); + + op_queue ops; + + for (int i = 0; i < max_signal_number; ++i) + { + registration* reg = registrations_[i]; + while (reg) + { + ops.push(*reg->queue_); + reg = reg->next_in_table_; + } + } + + scheduler_.abandon_operations(ops); +} + +void signal_set_service::notify_fork(execution_context::fork_event fork_ev) +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + switch (fork_ev) + { + case execution_context::fork_prepare: + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = true; + lock.unlock(); + reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_); + reactor_.cleanup_descriptor_data(reactor_data_); + } + break; + case execution_context::fork_parent: + if (state->fork_prepared_) + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + case execution_context::fork_child: + if (state->fork_prepared_) + { + asio::detail::signal_blocker blocker; + close_descriptors(); + open_descriptors(); + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + default: + break; + } +#else // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + (void)fork_ev; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::construct( + signal_set_service::implementation_type& impl) +{ + impl.signals_ = 0; +} + +void signal_set_service::destroy( + signal_set_service::implementation_type& impl) +{ + asio::error_code ignored_ec; + clear(impl, ignored_ec); + cancel(impl, ignored_ec); +} + +asio::error_code signal_set_service::add( + signal_set_service::implementation_type& impl, + int signal_number, asio::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the appropriate place to insert the registration. + registration** insertion_point = &impl.signals_; + registration* next = impl.signals_; + while (next && next->signal_number_ < signal_number) + { + insertion_point = &next->next_in_set_; + next = next->next_in_set_; + } + + // Only do something if the signal is not already registered. + if (next == 0 || next->signal_number_ != signal_number) + { + registration* new_registration = new registration; + +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Register for the signal if we're the first. + if (state->registration_count_[signal_number] == 0) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = asio_signal_handler; + sigfillset(&sa.sa_mask); + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(signal_number, asio_signal_handler) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + delete new_registration; + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Record the new registration in the set. + new_registration->signal_number_ = signal_number; + new_registration->queue_ = &impl.queue_; + new_registration->next_in_set_ = next; + *insertion_point = new_registration; + + // Insert registration into the registration table. + new_registration->next_in_table_ = registrations_[signal_number]; + if (registrations_[signal_number]) + registrations_[signal_number]->prev_in_table_ = new_registration; + registrations_[signal_number] = new_registration; + + ++state->registration_count_[signal_number]; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::remove( + signal_set_service::implementation_type& impl, + int signal_number, asio::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the signal number in the list of registrations. + registration** deletion_point = &impl.signals_; + registration* reg = impl.signals_; + while (reg && reg->signal_number_ < signal_number) + { + deletion_point = ®->next_in_set_; + reg = reg->next_in_set_; + } + + if (reg != 0 && reg->signal_number_ == signal_number) + { +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[signal_number] == 1) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(signal_number, SIG_DFL) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Remove the registration from the set. + *deletion_point = reg->next_in_set_; + + // Remove the registration from the registration table. + if (registrations_[signal_number] == reg) + registrations_[signal_number] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[signal_number]; + + delete reg; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::clear( + signal_set_service::implementation_type& impl, + asio::error_code& ec) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (registration* reg = impl.signals_) + { +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[reg->signal_number_] == 1) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(reg->signal_number_, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Remove the registration from the registration table. + if (registrations_[reg->signal_number_] == reg) + registrations_[reg->signal_number_] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[reg->signal_number_]; + + impl.signals_ = reg->next_in_set_; + delete reg; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::cancel( + signal_set_service::implementation_type& impl, + asio::error_code& ec) +{ + ASIO_HANDLER_OPERATION((scheduler_.context(), + "signal_set", &impl, 0, "cancel")); + + op_queue ops; + { + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (signal_op* op = impl.queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.queue_.pop(); + ops.push(op); + } + } + + scheduler_.post_deferred_completions(ops); + + ec = asio::error_code(); + return ec; +} + +void signal_set_service::deliver_signal(int signal_number) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + signal_set_service* service = state->service_list_; + while (service) + { + op_queue ops; + + registration* reg = service->registrations_[signal_number]; + while (reg) + { + if (reg->queue_->empty()) + { + ++reg->undelivered_; + } + else + { + while (signal_op* op = reg->queue_->front()) + { + op->signal_number_ = signal_number; + reg->queue_->pop(); + ops.push(op); + } + } + + reg = reg->next_in_table_; + } + + service->scheduler_.post_deferred_completions(ops); + + service = service->next_; + } +} + +void signal_set_service::add_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the first service to be created, open a new pipe. + if (state->service_list_ == 0) + open_descriptors(); +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + + // If a scheduler_ object is thread-unsafe then it must be the only + // scheduler used to create signal_set objects. + if (state->service_list_ != 0) + { + if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + service->scheduler_.concurrency_hint()) + || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + state->service_list_->scheduler_.concurrency_hint())) + { + std::logic_error ex( + "Thread-unsafe execution context objects require " + "exclusive access to signal handling."); + asio::detail::throw_exception(ex); + } + } + + // Insert service into linked list of all services. + service->next_ = state->service_list_; + service->prev_ = 0; + if (state->service_list_) + state->service_list_->prev_ = service; + state->service_list_ = service; + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Register for pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, service->reactor_data_, new pipe_read_op); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::remove_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + if (service->next_ || service->prev_ || state->service_list_ == service) + { +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Disable the pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.deregister_internal_descriptor( + read_descriptor, service->reactor_data_); + service->reactor_.cleanup_descriptor_data(service->reactor_data_); + lock.lock(); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // Remove service from linked list of all services. + if (state->service_list_ == service) + state->service_list_ = service->next_; + if (service->prev_) + service->prev_->next_ = service->next_; + if (service->next_) + service->next_->prev_= service->prev_; + service->next_ = 0; + service->prev_ = 0; + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the last service to be removed, close the pipe. + if (state->service_list_ == 0) + close_descriptors(); +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + } +} + +void signal_set_service::open_descriptors() +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + int pipe_fds[2]; + if (::pipe(pipe_fds) == 0) + { + state->read_descriptor_ = pipe_fds[0]; + ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK); + + state->write_descriptor_ = pipe_fds[1]; + ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "signal_set_service pipe"); + } +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::close_descriptors() +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + if (state->read_descriptor_ != -1) + ::close(state->read_descriptor_); + state->read_descriptor_ = -1; + + if (state->write_descriptor_ != -1) + ::close(state->write_descriptor_); + state->write_descriptor_ = -1; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::start_wait_op( + signal_set_service::implementation_type& impl, signal_op* op) +{ + scheduler_.work_started(); + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + registration* reg = impl.signals_; + while (reg) + { + if (reg->undelivered_ > 0) + { + --reg->undelivered_; + op->signal_number_ = reg->signal_number_; + scheduler_.post_deferred_completion(op); + return; + } + + reg = reg->next_in_set_; + } + + impl.queue_.push(op); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/socket_ops.ipp b/extern/asio-1.18.2/include/asio/detail/impl/socket_ops.ipp new file mode 100644 index 0000000..77edf9e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,3964 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_OPS_IPP +#define ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include +#include +#include +#include +#include +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include +# include +# include +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) +# if defined(ASIO_HAS_PTHREADS) +# include +# endif // defined(ASIO_HAS_PTHREADS) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_ops { + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +inline void clear_last_error() +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +#if !defined(ASIO_WINDOWS_RUNTIME) + +inline void get_last_error( + asio::error_code& ec, bool is_error_condition) +{ + if (!is_error_condition) + { + ec.assign(0, ec.category()); + } + else + { +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(WSAGetLastError(), + asio::error::get_system_category()); +#else + ec = asio::error_code(errno, + asio::error::get_system_category()); +#endif + } +} + +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, new_s == invalid_socket); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = ::setsockopt(new_s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec.assign(0, ec.category()); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return new_socket; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return invalid_socket; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) > *addrlen) + { + ec = asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return true; + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { + // We don't want the destructor to block, so set the socket to linger in + // the background. If the user doesn't like this behaviour then they need + // to explicitly close the socket. + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + asio::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = ::closesocket(s); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = ::close(s); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); + + if (result != 0 + && (ec == asio::error::would_block + || ec == asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); +# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + state &= ~non_blocking; + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = ::closesocket(s); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = ::close(s); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); + } + } + + return result; +} + +bool set_user_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#endif + + if (result >= 0) + { + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = asio::error::invalid_argument; + return false; + } + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#endif + + if (result >= 0) + { + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + int result = ::shutdown(s, what); + get_last_error(ec, result != 0); + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); +#if defined(__linux__) + if (result != 0 && ec == asio::error::try_again) + ec = asio::error::no_buffer_space; +#endif // defined(__linux__) + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != asio::error::in_progress + && ec != asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, -1, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = asio::error_code(connect_error, + asio::error::get_system_category()); +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_connect(socket_type s, asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + switch (ec.value()) + { + case ERROR_CONNECTION_REFUSED: + ec = asio::error::connection_refused; + break; + case ERROR_NETWORK_UNREACHABLE: + ec = asio::error::network_unreachable; + break; + case ERROR_HOST_UNREACHABLE: + ec = asio::error::host_unreachable; + break; + case ERROR_SEM_TIMEOUT: + ec = asio::error::timed_out; + break; + default: + break; + } + + if (!ec) + { + // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname + // and getpeername will work on the connected socket. + socket_ops::state_type state = 0; + const int so_update_connect_context = 0x7010; + socket_ops::setsockopt(s, state, SOL_SOCKET, + so_update_connect_context, 0, 0, ec); + } +} + +#endif // defined(ASIO_HAS_IOCP) + +bool non_blocking_connect(socket_type s, asio::error_code& ec) +{ + // Check if the connect operation has finished. This is required since we may + // get spurious readiness notifications from the reactor. +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval zero_timeout; + zero_timeout.tv_sec = 0; + zero_timeout.tv_usec = 0; + int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int ready = ::poll(&fds, 1, 0); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (ready == 0) + { + // The asynchronous connect operation is still in progress. + return false; + } + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = asio::error_code(connect_error, + asio::error::get_system_category()); + } + else + ec.assign(0, ec.category()); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = asio::error::operation_not_supported; + return socket_error_retval; +#else + int result = ::socketpair(af, type, protocol, sv); + get_last_error(ec, result != 0); + return result; +#endif +} + +bool sockatmark(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = ::ioctlsocket(s, SIOCATMARK, &value); +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = ::ioctl(s, SIOCATMARK, &value); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result < 0); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = ::sockatmark(s); + get_last_error(ec, result < 0); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = ::ioctlsocket(s, FIONREAD, &value); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = ::ioctl(s, FIONREAD, &value); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result < 0); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast(0) : static_cast(value); +} + +int listen(socket_type s, int backlog, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + int result = ::listen(s, backlog); + get_last_error(ec, result != 0); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(data); + b.len = static_cast(size); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(const_cast(data)); + b.len = static_cast(size); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + +signed_size_type recv(socket_type s, buf* bufs, size_t count, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type recv1(socket_type s, void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(s, &buf, 1, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = ::recv(s, static_cast(data), size, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_recv1(socket_type s, state_type state, void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = asio::error::eof; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, + int flags, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = ::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast(*addrlen); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); + *addrlen = msg.msg_namelen; + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template +inline signed_size_type call_recvfrom(SockLenType msghdr::*, + socket_type s, void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + signed_size_type result = ::recvfrom(s, static_cast(data), + size, flags, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +signed_size_type recvfrom1(socket_type s, void* data, size_t size, + int flags, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = static_cast(data); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, + &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = call_recvfrom(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_recvfrom1(socket_type s, state_type state, void* data, + size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recvfrom1(socket_type s, + void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, + int in_flags, int& out_flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + out_flags = 0; + return socket_ops::recv(s, bufs, count, in_flags, ec); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = ::recvmsg(s, &msg, in_flags); + get_last_error(ec, result < 0); + if (result >= 0) + out_flags = msg.msg_flags; + else + out_flags = 0; + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type send(socket_type s, const buf* bufs, size_t count, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = ::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = static_cast(count); +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type send1(socket_type s, const void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = ::WSASend(s, &buf, 1, + &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::send(s, + static_cast(data), size, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_send1(socket_type s, state_type state, const void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + int result = ::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast(addrlen); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = static_cast(count); +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template +inline signed_size_type call_sendto(SockLenType msghdr::*, + socket_type s, const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen) +{ + return ::sendto(s, static_cast(const_cast(data)), + size, flags, addr, (SockLenType)addrlen); +} + +signed_size_type sendto1(socket_type s, const void* data, size_t size, + int flags, const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, + flags, addr, static_cast(addrlen), 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = call_sendto(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_sendto1(socket_type s, state_type state, const void* data, + size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if !defined(ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // !defined(ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED); + get_last_error(ec, s == invalid_socket); + if (s == invalid_socket) + return s; + + if (af == ASIO_OS_DEF(AF_INET6)) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = ::socket(af, type, protocol); + get_last_error(ec, s == invalid_socket); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = ::setsockopt(s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = ::socket(af, type, protocol); + get_last_error(ec, s < 0); + return s; +#endif +} + +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec.assign(0, ec.category()); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + int result = sso(s, level, optname, + reinterpret_cast(optval), + static_cast(optlen)); + get_last_error(ec, result != 0); + return result; + } + } + ec = asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + int result = call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); + if (result == 0) + { +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(__OpenBSD__) || defined(__QNX__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec.assign(0, ec.category()); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + int tmp_optlen = static_cast(*optlen); + int result = gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen); + get_last_error(ec, result != 0); + *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec.assign(0, ec.category()); + } + return result; + } + } + ec = asio::error::fault; + return socket_error_retval; +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec.assign(0, ec.category()); + } + return result; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) \ + || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec.assign(0, ec.category()); + return 0; + } +#else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + (void)cached; +#endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + + int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); + return result; +} + +int ioctl(socket_type s, state_type& state, int cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = ::ioctlsocket(s, cmd, arg); +#elif defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + int result = ::ioctl(s, static_cast(cmd), arg); +#else + int result = ::ioctl(s, cmd, arg); +#endif + get_last_error(ec, result < 0); + if (result >= 0) + { + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the socket is already in + // the correct state. This ensures that the underlying socket is put into + // the state that has been requested by the user. If the ioctl syscall was + // successful then we need to update the flags to match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec) +{ +#if defined(__EMSCRIPTEN__) + exceptfds = 0; +#endif // defined(__EMSCRIPTEN__) +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec.assign(0, ec.category()); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + int result = ::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0); +#else + int result = ::select(nfds, readfds, writefds, exceptfds, timeout); +#endif + get_last_error(ec, result < 0); + return result; +} + +int poll_read(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + int result = ::select(s + 1, &fds, 0, 0, timeout); + get_last_error(ec, result < 0); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +int poll_write(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + int result = ::select(s + 1, 0, &fds, 0, timeout); + get_last_error(ec, result < 0); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +int poll_error(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + int result = ::select(s + 1, 0, 0, &fds, timeout); + get_last_error(ec, result < 0); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + if (state & user_set_non_blocking) + ec = asio::error::would_block; + return result; +} + +int poll_connect(socket_type s, int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval timeout_obj; + timeval* timeout; + if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout); + get_last_error(ec, result < 0); + return result; +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int result = ::poll(&fds, 1, msec); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS_RUNTIME) + using namespace std; // For sprintf. + const unsigned char* bytes = static_cast(src); + if (af == ASIO_OS_DEF(AF_INET)) + { + sprintf_s(dest, length, "%u.%u.%u.%u", + bytes[0], bytes[1], bytes[2], bytes[3]); + return dest; + } + else if (af == ASIO_OS_DEF(AF_INET6)) + { + size_t n = 0, b = 0, z = 0; + while (n < length && b < 16) + { + if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0) + { + do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0); + n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z; + } + else + { + n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "", + (static_cast(bytes[b]) << 8) | bytes[b + 1]); + b += 2; + } + } + if (scope_id) + n += sprintf_s(dest + n, length - n, "%%%lu", scope_id); + return dest; + } + else + { + ec = asio::error::address_family_not_supported; + return 0; + } +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == ASIO_OS_DEF(AF_INET)) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = ASIO_OS_DEF(AF_INET); + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = ASIO_OS_DEF(AF_INET6); + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = ::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length); + get_last_error(ec, true); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, + dest, static_cast(length), 0, 0); +#else + int result = ::WSAAddressToStringA(&address.base, + address_length, 0, dest, &string_length); + get_last_error(ec, true); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec.assign(0, ec.category()); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + const char* result = ::inet_ntop(af, src, dest, static_cast(length)); + get_last_error(ec, true); + if (result == 0 && !ec) + ec = asio::error::invalid_argument; + if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast(src); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if ((!is_link_local && !is_multicast_link_local) + || if_indextoname(static_cast(scope_id), if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS_RUNTIME) + using namespace std; // For sscanf. + unsigned char* bytes = static_cast(dest); + if (af == ASIO_OS_DEF(AF_INET)) + { + unsigned int b0, b1, b2, b3; + if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4) + { + ec = asio::error::invalid_argument; + return -1; + } + if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255) + { + ec = asio::error::invalid_argument; + return -1; + } + bytes[0] = static_cast(b0); + bytes[1] = static_cast(b1); + bytes[2] = static_cast(b2); + bytes[3] = static_cast(b3); + ec.assign(0, ec.category()); + return 1; + } + else if (af == ASIO_OS_DEF(AF_INET6)) + { + unsigned char* bytes = static_cast(dest); + std::memset(bytes, 0, 16); + unsigned char back_bytes[16] = { 0 }; + int num_front_bytes = 0, num_back_bytes = 0; + const char* p = src; + + enum { fword, fcolon, bword, scope, done } state = fword; + unsigned long current_word = 0; + while (state != done) + { + if (current_word > 0xFFFF) + { + ec = asio::error::invalid_argument; + return -1; + } + + switch (state) + { + case fword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes == 16) + { + ec = asio::error::invalid_argument; + return -1; + } + + bytes[num_front_bytes++] = (current_word >> 8) & 0xFF; + bytes[num_front_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = fcolon, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + } + break; + + case fcolon: + if (*p == ':') + state = bword, ++p; + else + state = fword; + break; + + case bword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes + num_back_bytes == 16) + { + ec = asio::error::invalid_argument; + return -1; + } + + back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF; + back_bytes[num_back_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = bword, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + } + break; + + case scope: + if (*p >= '0' && *p <= '9') + current_word = current_word * 10 + *p++ - '0'; + else if (*p == 0) + *scope_id = current_word, state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + break; + + default: + break; + } + } + + for (int i = 0; i < num_back_bytes; ++i) + bytes[16 - num_back_bytes + i] = back_bytes[i]; + + ec.assign(0, ec.category()); + return 1; + } + else + { + ec = asio::error::address_family_not_supported; + return -1; + } +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6)) + { + ec = asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + int num_wide_chars = static_cast(strlen(src)) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = ::WSAStringToAddressW(wide_buffer, + af, 0, &address.base, &address_length); + get_last_error(ec, true); +#else + int result = ::WSAStringToAddressA(const_cast(src), + af, 0, &address.base, &address_length); + get_last_error(ec, true); +#endif + + if (af == ASIO_OS_DEF(AF_INET)) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec.assign(0, ec.category()); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast(dest)->s_addr = INADDR_NONE; + ec.assign(0, ec.category()); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec.assign(0, ec.category()); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + if (result != socket_error_retval) + ec.assign(0, ec.category()); + + return result == socket_error_retval ? -1 : 1; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For strchr, memcpy and atoi. + + // On some platforms, inet_pton fails if an address string contains a scope + // id. Detect and remove the scope id before passing the string to inet_pton. + const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6)); + const char* if_name = is_v6 ? strchr(src, '%') : 0; + char src_buf[max_addr_v6_str_len + 1]; + const char* src_ptr = src; + if (if_name != 0) + { + if (if_name - src > max_addr_v6_str_len) + { + ec = asio::error::invalid_argument; + return 0; + } + memcpy(src_buf, src, if_name - src); + src_buf[if_name - src] = 0; + src_ptr = src_buf; + } + + int result = ::inet_pton(af, src_ptr, dest); + get_last_error(ec, true); + if (result <= 0 && !ec) + ec = asio::error::invalid_argument; + if (result > 0 && is_v6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (if_name != 0) + { + in6_addr_type* ipv6_address = static_cast(dest); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if (is_link_local || is_multicast_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + try + { + using namespace Windows::Foundation::Collections; + using namespace Windows::Networking; + using namespace Windows::Networking::Connectivity; + IVectorView^ hostnames = NetworkInformation::GetHostNames(); + for (unsigned i = 0; i < hostnames->Size; ++i) + { + HostName^ hostname = hostnames->GetAt(i); + if (hostname->Type == HostNameType::DomainName) + { + std::wstring_convert> converter; + std::string raw_name = converter.to_bytes(hostname->RawName->Data()); + if (namelen > 0 && raw_name.size() < static_cast(namelen)) + { + strcpy_s(name, namelen, raw_name.c_str()); + return 0; + } + } + } + return -1; + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return -1; + } +#else // defined(ASIO_WINDOWS_RUNTIME) + int result = ::gethostname(name, namelen); + get_last_error(ec, result != 0); + return result; +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if !defined(ASIO_HAS_GETADDRINFO) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline asio::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case HOST_NOT_FOUND: + return asio::error::host_not_found; + case TRY_AGAIN: + return asio::error::host_not_found_try_again; + case NO_RECOVERY: + return asio::error::no_recovery; + case NO_DATA: + return asio::error::no_data; + default: + ASIO_ASSERT(false); + return asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = ::gethostbyaddr(addr, length, af); + get_last_error(ec, !retval); + if (!retval) + return 0; + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = ::gethostbyaddr_r(addr, length, + af, result, buffer, buflength, &error); + get_last_error(ec, !retval); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = ::getipnodebyaddr(addr, length, af, &error); + get_last_error(ec, !retval); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + clear_last_error(); + ::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &retval, &error); + get_last_error(ec, true); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = ::gethostbyname(name); + get_last_error(ec, !retval); + if (!retval) + return 0; + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error); + get_last_error(ec, !retval); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = ::getipnodebyname(name, af, ai_flags, &error); + get_last_error(ec, !retval); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + clear_last_error(); + ::gethostbyname_r(name, result, buffer, buflength, &retval, &error); + get_last_error(ec, true); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = "0.0.0.0"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = "0::0"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "0::0"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if defined(ASIO_HAS_SECURE_RTL) + strcpy_s(target, max_size, source); +#else // defined(ASIO_HAS_SECURE_RTL) + *target = 0; + if (max_size > 0) + strncat(target, source, max_size - 1); +#endif // defined(ASIO_HAS_SECURE_RTL) +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = gai_alloc(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = ASIO_OS_DEF(AF_INET); + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = gai_alloc(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = ASIO_OS_DEF(AF_INET6); + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(static_cast(serv[0]))) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case ASIO_OS_DEF(AF_UNSPEC): + break; + case ASIO_OS_DEF(AF_INET): + case ASIO_OS_DEF(AF_INET6): + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = ASIO_OS_DEF(AF_UNSPEC); + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + asio::error_code ec; + if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), + sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != ASIO_OS_DEF(AF_INET)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == ASIO_OS_DEF(AF_INET)) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), + sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != ASIO_OS_DEF(AF_INET6)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == ASIO_OS_DEF(AF_INET6)) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, + ASIO_OS_DEF(AF_INET6)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == asio::error::host_not_found) + return EAI_NONAME; + if (ec == asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == asio::error::no_recovery) + return EAI_FAIL; + if (ec == asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline asio::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + asio::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case ASIO_OS_DEF(AF_INET): + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast(sa)->sin_port; + break; + case ASIO_OS_DEF(AF_INET6): + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast(sa)->sin6_port; + break; + default: + return ec = asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if defined(ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(ASIO_HAS_SECURE_RTL) + } + else + { +#if defined(ASIO_HAS_PTHREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(ASIO_HAS_PTHREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if defined(ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(ASIO_HAS_SECURE_RTL) + } +#if defined(ASIO_HAS_PTHREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(ASIO_HAS_PTHREADS) + } + } + + ec.assign(0, ec.category()); + return ec; +} + +#endif // !defined(ASIO_HAS_GETADDRINFO) + +inline asio::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case EAI_AGAIN: + return asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return asio::error::invalid_argument; + case EAI_FAIL: + return asio::error::no_recovery; + case EAI_FAMILY: + return asio::error::address_family_not_supported; + case EAI_MEMORY: + return asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return asio::error::host_not_found; + case EAI_SERVICE: + return asio::error::service_not_found; + case EAI_SOCKTYPE: + return asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return asio::error_code( + WSAGetLastError(), asio::error::get_system_category()); +#else + return asio::error_code( + errno, asio::error::get_system_category()); +#endif + } +} + +asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + host = (host && *host) ? host : 0; + service = (service && *service) ? service : 0; + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); +#if defined(__MACH__) && defined(__APPLE__) + using namespace std; // For isdigit and atoi. + if (error == 0 && service && isdigit(static_cast(service[0]))) + { + u_short_type port = host_to_network_short(atoi(service)); + for (addrinfo_type* ai = *result; ai; ai = ai->ai_next) + { + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + if (sinptr->sin_port == 0) + sinptr->sin_port = port; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + if (sin6ptr->sin6_port == 0) + sin6ptr->sin6_port = port; + break; + } + default: + break; + } + } + } +#endif + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +asio::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + addr = reinterpret_cast(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +u_long_type network_to_host_long(u_long_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast(&value); + u_long_type result = (static_cast(value_p[0]) << 24) + | (static_cast(value_p[1]) << 16) + | (static_cast(value_p[2]) << 8) + | static_cast(value_p[3]); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return ntohl(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_long_type host_to_network_long(u_long_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + u_long_type result; + unsigned char* result_p = reinterpret_cast(&result); + result_p[0] = static_cast((value >> 24) & 0xFF); + result_p[1] = static_cast((value >> 16) & 0xFF); + result_p[2] = static_cast((value >> 8) & 0xFF); + result_p[3] = static_cast(value & 0xFF); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return htonl(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_short_type network_to_host_short(u_short_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast(&value); + u_short_type result = (static_cast(value_p[0]) << 8) + | static_cast(value_p[1]); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return ntohs(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_short_type host_to_network_short(u_short_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + u_short_type result; + unsigned char* result_p = reinterpret_cast(&result); + result_p[0] = static_cast((value >> 8) & 0xFF); + result_p[1] = static_cast(value & 0xFF); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return htons(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/socket_select_interrupter.ipp b/extern/asio-1.18.2/include/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 0000000..81813db --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,185 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + open_descriptors(); +} + +void socket_select_interrupter::open_descriptors() +{ + asio::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY)) + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + close_descriptors(); +} + +void socket_select_interrupter::close_descriptors() +{ + asio::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = invalid_socket; + read_descriptor_ = invalid_socket; + + open_descriptors(); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + asio::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + asio::error_code ec; + for (;;) + { + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + if (bytes_read == sizeof(data)) + continue; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return true; + return false; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.hpp b/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.hpp new file mode 100644 index 0000000..bf2555c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.hpp @@ -0,0 +1,352 @@ +// +// detail/impl/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP +#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/defer.hpp" +#include "asio/dispatch.hpp" +#include "asio/post.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class strand_executor_service::allocator_binder +{ +public: + typedef Allocator allocator_type; + + allocator_binder(ASIO_MOVE_ARG(F) f, const Allocator& a) + : f_(ASIO_MOVE_CAST(F)(f)), + allocator_(a) + { + } + + allocator_binder(const allocator_binder& other) + : f_(other.f_), + allocator_(other.allocator_) + { + } + +#if defined(ASIO_HAS_MOVE) + allocator_binder(allocator_binder&& other) + : f_(ASIO_MOVE_CAST(F)(other.f_)), + allocator_(ASIO_MOVE_CAST(allocator_type)(other.allocator_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + allocator_type get_allocator() const ASIO_NOEXCEPT + { + return allocator_; + } + + void operator()() + { + f_(); + } + +private: + F f_; + allocator_type allocator_; +}; + +template +class strand_executor_service::invoker::value + >::type> +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)), + executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + if (push_waiting_to_ready(this_->impl_)) + { + recycling_allocator allocator; + execution::execute( + asio::prefer( + asio::require(this_->executor_, + execution::blocking.never), + execution::allocator(allocator)), + ASIO_MOVE_CAST(invoker)(*this_)); + } + } + }; + + void operator()() + { + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + run_ready_handlers(impl_); + } + +private: + typedef typename decay< + typename prefer_result< + Executor, + execution::outstanding_work_t::tracked_t + >::type + >::type executor_type; + + implementation_type impl_; + executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template +class strand_executor_service::invoker::value + >::type> +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + work_(ex) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + work_(other.work_) + { + } + +#if defined(ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)), + work_(ASIO_MOVE_CAST(executor_work_guard)(other.work_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + if (push_waiting_to_ready(this_->impl_)) + { + Executor ex(this_->work_.get_executor()); + recycling_allocator allocator; + ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator); + } + } + }; + + void operator()() + { + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + run_ready_handlers(impl_); + } + +private: + implementation_type impl_; + executor_work_guard work_; +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, + typename enable_if< + can_query >::value + >::type*) +{ + return strand_executor_service::do_execute(impl, ex, + ASIO_MOVE_CAST(Function)(function), + asio::query(ex, execution::allocator)); +} + +template +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, + typename enable_if< + !can_query >::value + >::type*) +{ + return strand_executor_service::do_execute(impl, ex, + ASIO_MOVE_CAST(Function)(function), + std::allocator()); +} + +template +void strand_executor_service::do_execute(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // If the executor is not never-blocking, and we are already in the strand, + // then the function can run immediately. + if (asio::query(ex, execution::blocking) != execution::blocking.never + && running_in_this_thread(impl)) + { + // Make a local, non-const copy of the function. + function_type tmp(ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "execute")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + execution::execute(ex, invoker(impl, ex)); + } +} + +template +void strand_executor_service::dispatch(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // If we are already in the strand then the function can run immediately. + if (running_in_this_thread(impl)) + { + // Make a local, non-const copy of the function. + function_type tmp(ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "dispatch")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + asio::dispatch(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } +} + +// Request invocation of the given function and return immediately. +template +void strand_executor_service::post(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "post")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + asio::post(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } +} + +// Request invocation of the given function and return immediately. +template +void strand_executor_service::defer(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "defer")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + asio::defer(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.ipp new file mode 100644 index 0000000..c97b6df --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/strand_executor_service.ipp @@ -0,0 +1,158 @@ +// +// detail/impl/strand_executor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/strand_executor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +strand_executor_service::strand_executor_service(execution_context& ctx) + : execution_context_service_base(ctx), + mutex_(), + salt_(0), + impl_list_(0) +{ +} + +void strand_executor_service::shutdown() +{ + op_queue ops; + + asio::detail::mutex::scoped_lock lock(mutex_); + + strand_impl* impl = impl_list_; + while (impl) + { + impl->mutex_->lock(); + impl->shutdown_ = true; + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + impl->mutex_->unlock(); + impl = impl->next_; + } +} + +strand_executor_service::implementation_type +strand_executor_service::create_implementation() +{ + implementation_type new_impl(new strand_impl); + new_impl->locked_ = false; + new_impl->shutdown_ = false; + + asio::detail::mutex::scoped_lock lock(mutex_); + + // Select a mutex from the pool of shared mutexes. + std::size_t salt = salt_++; + std::size_t mutex_index = reinterpret_cast(new_impl.get()); + mutex_index += (reinterpret_cast(new_impl.get()) >> 3); + mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2); + mutex_index = mutex_index % num_mutexes; + if (!mutexes_[mutex_index].get()) + mutexes_[mutex_index].reset(new mutex); + new_impl->mutex_ = mutexes_[mutex_index].get(); + + // Insert implementation into linked list of all implementations. + new_impl->next_ = impl_list_; + new_impl->prev_ = 0; + if (impl_list_) + impl_list_->prev_ = new_impl.get(); + impl_list_ = new_impl.get(); + new_impl->service_ = this; + + return new_impl; +} + +strand_executor_service::strand_impl::~strand_impl() +{ + asio::detail::mutex::scoped_lock lock(service_->mutex_); + + // Remove implementation from linked list of all implementations. + if (service_->impl_list_ == this) + service_->impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; +} + +bool strand_executor_service::enqueue(const implementation_type& impl, + scheduler_operation* op) +{ + impl->mutex_->lock(); + if (impl->shutdown_) + { + impl->mutex_->unlock(); + op->destroy(); + return false; + } + else if (impl->locked_) + { + // Some other function already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_->unlock(); + return false; + } + else + { + // The function is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_->unlock(); + impl->ready_queue_.push(op); + return true; + } +} + +bool strand_executor_service::running_in_this_thread( + const implementation_type& impl) +{ + return !!call_stack::contains(impl.get()); +} + +bool strand_executor_service::push_waiting_to_ready(implementation_type& impl) +{ + impl->mutex_->lock(); + impl->ready_queue_.push(impl->waiting_queue_); + bool more_handlers = impl->locked_ = !impl->ready_queue_.empty(); + impl->mutex_->unlock(); + return more_handlers; +} + +void strand_executor_service::run_ready_handlers(implementation_type& impl) +{ + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl.get()); + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + asio::error_code ec; + while (scheduler_operation* o = impl->ready_queue_.front()) + { + impl->ready_queue_.pop(); + o->complete(impl.get(), ec, 0); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/strand_service.hpp b/extern/asio-1.18.2/include/asio/detail/impl/strand_service.hpp new file mode 100644 index 0000000..3e395d6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/strand_service.hpp @@ -0,0 +1,87 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + locked_(false) +{ +} + +template +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler& handler) +{ + // If we are already in the strand then the handler can run immediately. + if (running_in_this_thread(impl)) + { + fenced_block b(fenced_block::full); + asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_context_.get_executor()); + + ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "dispatch")); + + operation* o = p.p; + p.v = p.p = 0; + do_dispatch(impl, o); +} + +// Request the io_context to invoke the given handler and return immediately. +template +void strand_service::post(strand_service::implementation_type& impl, + Handler& handler) +{ + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_context_.get_executor()); + + ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "post")); + + do_post(impl, p.p, is_continuation); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/strand_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/strand_service.ipp new file mode 100644 index 0000000..58d657c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/strand_service.ipp @@ -0,0 +1,202 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/call_stack.hpp" +#include "asio/detail/strand_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_context_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_, true); + } +}; + +strand_service::strand_service(asio::io_context& io_context) + : asio::detail::service_base(io_context), + io_context_(io_context), + io_context_impl_(asio::use_service(io_context)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown() +{ + op_queue ops; + + asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + { + if (strand_impl* impl = implementations_[i].get()) + { + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + } + } +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + std::size_t salt = salt_++; +#if defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = salt; +#else // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = reinterpret_cast(&impl); + index += (reinterpret_cast(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); +#endif // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + index = index % num_implementations; + + if (!implementations_[index].get()) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +bool strand_service::running_in_this_thread( + const implementation_type& impl) const +{ + return call_stack::contains(impl) != 0; +} + +struct strand_service::on_dispatch_exit +{ + io_context_impl* io_context_impl_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + io_context_impl_->post_immediate_completion(impl_, false); + } +}; + +void strand_service::do_dispatch(implementation_type& impl, operation* op) +{ + // If we are running inside the io_context, and no other handler already + // holds the strand lock, then the handler can run immediately. + bool can_dispatch = io_context_impl_.can_dispatch(); + impl->mutex_.lock(); + if (can_dispatch && !impl->locked_) + { + // Immediate invocation is allowed. + impl->locked_ = true; + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_context_impl_, impl }; + (void)on_exit; + + op->complete(&io_context_impl_, asio::error_code(), 0); + return; + } + + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_impl_.post_immediate_completion(impl, false); + } +} + +void strand_service::do_post(implementation_type& impl, + operation* op, bool is_continuation) +{ + impl->mutex_.lock(); + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_impl_.post_immediate_completion(impl, is_continuation); + } +} + +void strand_service::do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast(base); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit; + on_exit.owner_ = static_cast(owner); + on_exit.impl_ = impl; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + while (operation* o = impl->ready_queue_.front()) + { + impl->ready_queue_.pop(); + o->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/thread_context.ipp b/extern/asio-1.18.2/include/asio/detail/impl/thread_context.ipp new file mode 100644 index 0000000..65cc275 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/thread_context.ipp @@ -0,0 +1,35 @@ +// +// detail/impl/thread_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP +#define ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +thread_info_base* thread_context::top_of_thread_call_stack() +{ + return thread_call_stack::top(); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/throw_error.ipp b/extern/asio-1.18.2/include/asio/detail/impl/throw_error.ipp new file mode 100644 index 0000000..c22cefc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/throw_error.ipp @@ -0,0 +1,60 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_THROW_ERROR_IPP +#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/throw_exception.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void do_throw_error(const asio::error_code& err) +{ + asio::system_error e(err); + asio::detail::throw_exception(e); +} + +void do_throw_error(const asio::error_code& err, const char* location) +{ + // boostify: non-boost code starts here +#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // Microsoft's implementation of std::system_error is non-conformant in that + // it ignores the error code's message when a "what" string is supplied. We'll + // work around this by explicitly formatting the "what" string. + std::string what_msg = location; + what_msg += ": "; + what_msg += err.message(); + asio::system_error e(err, what_msg); + asio::detail::throw_exception(e); +#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // boostify: non-boost code ends here + asio::system_error e(err, location); + asio::detail::throw_exception(e); + // boostify: non-boost code starts here +#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // boostify: non-boost code ends here +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_ptime.ipp b/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_ptime.ipp new file mode 100644 index 0000000..7873a95 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_ptime.ipp @@ -0,0 +1,91 @@ +// +// detail/impl/timer_queue_ptime.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) + +#include "asio/detail/timer_queue_ptime.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue >::timer_queue() +{ +} + +timer_queue >::~timer_queue() +{ +} + +bool timer_queue >::enqueue_timer( + const time_type& time, per_timer_data& timer, wait_op* op) +{ + return impl_.enqueue_timer(time, timer, op); +} + +bool timer_queue >::empty() const +{ + return impl_.empty(); +} + +long timer_queue >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue >::get_ready_timers( + op_queue& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue >::get_all_timers( + op_queue& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue >::cancel_timer( + per_timer_data& timer, op_queue& ops, std::size_t max_cancelled) +{ + return impl_.cancel_timer(timer, ops, max_cancelled); +} + +void timer_queue >::move_timer( + per_timer_data& target, per_timer_data& source) +{ + impl_.move_timer(target, source); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_set.ipp b/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 0000000..04c62c3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,101 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_queue_set.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::erase(timer_queue_base* q) +{ + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::wait_duration_msec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; +} + +long timer_queue_set::wait_duration_usec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; +} + +void timer_queue_set::get_ready_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_event.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_event.ipp new file mode 100644 index 0000000..d442c4d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_event.ipp @@ -0,0 +1,76 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_EVENT_IPP +#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_event.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_event::win_event() + : state_(0) +{ +#if defined(ASIO_WINDOWS_APP) + events_[0] = ::CreateEventExW(0, 0, + CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); +#else // defined(ASIO_WINDOWS_APP) + events_[0] = ::CreateEventW(0, true, false, 0); +#endif // defined(ASIO_WINDOWS_APP) + if (!events_[0]) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); + } + +#if defined(ASIO_WINDOWS_APP) + events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS); +#else // defined(ASIO_WINDOWS_APP) + events_[1] = ::CreateEventW(0, false, false, 0); +#endif // defined(ASIO_WINDOWS_APP) + if (!events_[1]) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(events_[0]); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); + } +} + +win_event::~win_event() +{ + ::CloseHandle(events_[0]); + ::CloseHandle(events_[1]); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_handle_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 0000000..7cefc15 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,525 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(asio::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create a non-signalled manual-reset event, for GetOverlappedResult. + hEvent = ::CreateEventW(0, TRUE, FALSE, 0); + if (hEvent) + { + // As documented in GetQueuedCompletionStatus, setting the low order + // bit of this event prevents our synchronous writes from being treated + // as completion port events. + DWORD_PTR tmp = reinterpret_cast(hEvent); + hEvent = reinterpret_cast(tmp | 1); + } + else + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service(execution_context& context) + : execution_context_service_base(context), + iocp_service_(asio::use_service(context)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_construct( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service::implementation_type& other_impl) +{ + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_assign( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service& other_service, + win_iocp_handle_service::implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(handle, ec)) + return ec; + + impl.handle_ = handle; + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "close")); + + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + else + { + ec = asio::error_code(); + } + + return ec; +} + +asio::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = reinterpret_cast( + reinterpret_cast(cancel_io_ex_ptr)); + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::const_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (buffer.size() == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (buffer.size() == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::mutable_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (buffer.size() == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Read some data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (buffer.size() == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "close")); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.hpp b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.hpp new file mode 100644 index 0000000..9f7f9bb --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.hpp @@ -0,0 +1,104 @@ +// +// detail/impl/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void win_iocp_io_context::add_timer_queue( + timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void win_iocp_io_context::remove_timer_queue( + timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void win_iocp_io_context::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + { + post_immediate_completion(op, false); + return; + } + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, timer, op); + work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t win_iocp_io_context::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + post_deferred_completions(ops); + return n; +} + +template +void win_iocp_io_context::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.ipp new file mode 100644 index 0000000..37e3250 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_io_context.ipp @@ -0,0 +1,608 @@ +// +// detail/impl/win_iocp_io_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_io_context::thread_function +{ + explicit thread_function(win_iocp_io_context* s) + : this_(s) + { + } + + void operator()() + { + asio::error_code ec; + this_->run(ec); + } + + win_iocp_io_context* this_; +}; + +struct win_iocp_io_context::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_context_->work_finished(); + } + + win_iocp_io_context* io_context_; +}; + +struct win_iocp_io_context::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_context_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_context_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_context_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_context* io_context_; +}; + +win_iocp_io_context::win_iocp_io_context( + asio::execution_context& ctx, int concurrency_hint, bool own_thread) + : execution_context_service_base(ctx), + iocp_(), + outstanding_work_(0), + stopped_(0), + stop_event_posted_(0), + shutdown_(0), + gqcs_timeout_(get_gqcs_timeout()), + dispatch_required_(0), + concurrency_hint_(concurrency_hint) +{ + ASIO_HANDLER_TRACKING_INIT; + + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "iocp"); + } + + if (own_thread) + { + ::InterlockedIncrement(&outstanding_work_); + thread_.reset(new asio::detail::thread(thread_function(this))); + } +} + +win_iocp_io_context::~win_iocp_io_context() +{ + if (thread_.get()) + { + stop(); + thread_->join(); + thread_.reset(); + } +} + +void win_iocp_io_context::shutdown() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_.get()) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + if (thread_.get()) + { + stop(); + thread_->join(); + thread_.reset(); + ::InterlockedDecrement(&outstanding_work_); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, gqcs_timeout_); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } + } + + if (timer_thread_.get()) + timer_thread_->join(); +} + +asio::error_code win_iocp_io_context::register_handle( + HANDLE handle, asio::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + return ec; +} + +size_t win_iocp_io_context::run(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(INFINITE, this_thread, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::run_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(INFINITE, this_thread, ec); +} + +size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec); +} + +size_t win_iocp_io_context::poll(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(0, this_thread, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::poll_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(0, this_thread, ec); +} + +void win_iocp_io_context::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pqcs"); + } + } + } +} + +bool win_iocp_io_context::can_dispatch() +{ + return thread_call_stack::contains(this) != 0; +} + +void win_iocp_io_context::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + +void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::post_deferred_completions( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::abandon_operations( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } +} + +void win_iocp_io_context::on_pending(win_iocp_operation* op) +{ + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_context::do_one(DWORD msec, + win_iocp_thread_info& this_thread, asio::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, + &bytes_transferred, &completion_key, &overlapped, + msec < gqcs_timeout_ ? msec : gqcs_timeout_); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast(overlapped); + asio::error_code result_ec(last_error, + asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = asio::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(this, result_ec, bytes_transferred); + this_thread.rethrow_pending_exception(); + ec = asio::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + // If we're waiting indefinitely we need to keep going until we get a + // real handler. + if (msec == INFINITE) + continue; + + ec = asio::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // Indicate that there is no longer an in-flight stop event. + ::InterlockedExchange(&stop_event_posted_, 0); + + // The stopped_ flag is always checked to ensure that any leftover + // stop events from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + } + + ec = asio::error_code(); + return 0; + } + } + } +} + +DWORD win_iocp_io_context::get_gqcs_timeout() +{ + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = 6ul; + + const uint64_t condition_mask = ::VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL); + + if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask)) + return INFINITE; + + return default_gqcs_timeout; +} + +void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "timer"); + } + + LARGE_INTEGER timeout; + timeout.QuadPart = -max_timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + + if (!timer_thread_.get()) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.erase(&queue); +} + +void win_iocp_io_context::update_timeout() +{ + if (timer_thread_.get()) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_serial_port_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 0000000..8b47920 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,192 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#include +#include "asio/detail/win_iocp_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + execution_context& context) + : execution_context_service_base(context), + handle_service_(context) +{ +} + +void win_iocp_serial_port_service::shutdown() +{ +} + +asio::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + // For convenience, add a leading \\.\ sequence if not already present. + std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; + + // Open a handle to the serial port. + ::HANDLE handle = ::CreateFileA(name.c_str(), + GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set some default serial port parameters. This implementation does not + // support changing all of these, so they might as well be in a known state. + dcb.fBinary = TRUE; // Win32 only supports binary mode. + dcb.fNull = FALSE; // Do not ignore NULL characters. + dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + dcb.BaudRate = CBR_9600; // 9600 baud by default + dcb.ByteSize = 8; // 8 bit bytes + dcb.fOutxCtsFlow = FALSE; // No flow control + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.fParity = FALSE; // No parity + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; // One stop bit + if (!::SetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set up timeouts so that the serial port will behave similarly to a + // network socket. Reads wait for at least one byte, then return with + // whatever they have. Writes return once everything is out the door. + ::COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + if (!::SetCommTimeouts(handle, &timeouts)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // We're done. Take ownership of the serial port handle. + if (handle_service_.assign(impl, handle, ec)) + ::CloseHandle(handle); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + using namespace std; // For memcpy. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_socket_service_base.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 0000000..da5beaf --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,801 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_socket_service_base::win_iocp_socket_service_base( + execution_context& context) + : context_(context), + iocp_service_(use_service(context)), + reactor_(0), + connect_ex_(0), + nt_set_info_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::base_shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_construct( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base::base_implementation_type& other_impl) + ASIO_NOEXCEPT +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + win_iocp_socket_service_base::base_implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + return ec; +} + +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + +asio::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = reinterpret_cast( + reinterpret_cast(cancel_io_ex_ptr)); + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } +#if defined(ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } +#else // defined(ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = asio::error::operation_not_supported; + } +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Cancel any operations started via the reactor. + if (!ec) + { + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->cancel_ops(impl.socket_, impl.reactor_data_); + } + + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast(buffer_count), &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? select_reactor::except_op : select_reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, asio::error::already_open); + else + { + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_reactor_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op) +{ + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false); + return; + } + else + op->ec_ = asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, const socket_addr_type* addr, + std::size_t addrlen, win_iocp_socket_connect_op_base* op) +{ + // If ConnectEx is available, use that. + if (family == ASIO_OS_DEF(AF_INET) + || family == ASIO_OS_DEF(AF_INET6)) + { + if (connect_ex_fn connect_ex = get_connect_ex(impl, type)) + { + union address_union + { + socket_addr_type base; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } a; + + using namespace std; // For memset. + memset(&a, 0, sizeof(a)); + a.base.sa_family = family; + + socket_ops::bind(impl.socket_, &a.base, + family == ASIO_OS_DEF(AF_INET) + ? sizeof(a.v4) : sizeof(a.v6), op->ec_); + if (op->ec_ && op->ec_ != asio::error::invalid_argument) + { + iocp_service_.post_immediate_completion(op, false); + return; + } + + op->connect_ex_ = true; + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + BOOL result = connect_ex(impl.socket_, + addr, static_cast(addrlen), 0, 0, 0, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + return; + } + } + + // Otherwise, fall back to a reactor-based implementation. + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + r.start_op(select_reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false, false); + return; + } + } + } + + r.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +select_reactor& win_iocp_socket_service_base::get_reactor() +{ + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(context_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; +} + +win_iocp_socket_service_base::connect_ex_fn +win_iocp_socket_service_base::get_connect_ex( + win_iocp_socket_service_base::base_implementation_type& impl, int type) +{ +#if defined(ASIO_DISABLE_CONNECTEX) + (void)impl; + (void)type; + return 0; +#else // defined(ASIO_DISABLE_CONNECTEX) + if (type != ASIO_OS_DEF(SOCK_STREAM) + && type != ASIO_OS_DEF(SOCK_SEQPACKET)) + return 0; + + void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0); + if (!ptr) + { + GUID guid = { 0x25a207b9, 0xddf3, 0x4660, + { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } }; + + DWORD bytes = 0; + if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0) + { + // Set connect_ex_ to a special value to indicate that ConnectEx is + // unavailable. That way we won't bother trying to look it up again. + ptr = this; + } + + interlocked_exchange_pointer(&connect_ex_, ptr); + } + + return reinterpret_cast(ptr == this ? 0 : ptr); +#endif // defined(ASIO_DISABLE_CONNECTEX) +} + +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast(ptr == this ? 0 : ptr); +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedCompareExchange( + reinterpret_cast(dest), reinterpret_cast(exch), + reinterpret_cast(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedExchange( + reinterpret_cast(dest), reinterpret_cast(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_mutex.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_mutex.ipp new file mode 100644 index 0000000..8a2db6f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,84 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_MUTEX_IPP +#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_mutex.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_object_handle_service.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_object_handle_service.ipp new file mode 100644 index 0000000..0c44a41 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_object_handle_service.ipp @@ -0,0 +1,448 @@ +// +// detail/impl/win_object_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// 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 ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include "asio/detail/win_object_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_object_handle_service::win_object_handle_service(execution_context& context) + : execution_context_service_base(context), + scheduler_(asio::use_service(context)), + mutex_(), + impl_list_(0), + shutdown_(false) +{ +} + +void win_object_handle_service::shutdown() +{ + mutex::scoped_lock lock(mutex_); + + // Setting this flag to true prevents new objects from being registered, and + // new asynchronous wait operations from being started. We only need to worry + // about cleaning up the operations that are currently in progress. + shutdown_ = true; + + op_queue ops; + for (implementation_type* impl = impl_list_; impl; impl = impl->next_) + ops.push(impl->op_queue_); + + lock.unlock(); + + scheduler_.abandon_operations(ops); +} + +void win_object_handle_service::construct( + win_object_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.owner_ = this; + + // Insert implementation into linked list of all implementations. + mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } +} + +void win_object_handle_service::move_construct( + win_object_handle_service::implementation_type& impl, + win_object_handle_service::implementation_type& other_impl) +{ + mutex::scoped_lock lock(mutex_); + + // Insert implementation into linked list of all implementations. + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::move_assign( + win_object_handle_service::implementation_type& impl, + win_object_handle_service& other_service, + win_object_handle_service::implementation_type& other_impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + mutex::scoped_lock lock(mutex_); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::destroy( + win_object_handle_service::implementation_type& impl) +{ + mutex::scoped_lock lock(mutex_); + + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "close")); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.op_queue_.pop(); + ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + + scheduler_.post_deferred_completions(ops); + } +} + +asio::error_code win_object_handle_service::assign( + win_object_handle_service::implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + impl.handle_ = handle; + ec = asio::error_code(); + return ec; +} + +asio::error_code win_object_handle_service::close( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "close")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + impl.op_queue_.pop(); + op->ec_ = asio::error::operation_aborted; + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + if (::CloseHandle(impl.handle_)) + { + impl.handle_ = INVALID_HANDLE_VALUE; + ec = asio::error_code(); + } + else + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + + scheduler_.post_deferred_completions(completed_ops); + } + else + { + ec = asio::error_code(); + } + + return ec; +} + +asio::error_code win_object_handle_service::cancel( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "cancel")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ec = asio::error_code(); + + scheduler_.post_deferred_completions(completed_ops); + } + else + { + ec = asio::error::bad_descriptor; + } + + return ec; +} + +void win_object_handle_service::wait( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + switch (::WaitForSingleObject(impl.handle_, INFINITE)) + { + case WAIT_FAILED: + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + break; + } + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + default: + ec = asio::error_code(); + break; + } +} + +void win_object_handle_service::start_wait_op( + win_object_handle_service::implementation_type& impl, wait_op* op) +{ + scheduler_.work_started(); + + if (is_open(impl)) + { + mutex::scoped_lock lock(mutex_); + + if (!shutdown_) + { + impl.op_queue_.push(op); + + // Only the first operation to be queued gets to register a wait callback. + // Subsequent operations have to wait for the first to finish. + if (impl.op_queue_.front() == op) + register_wait_callback(impl, lock); + } + else + { + lock.unlock(); + scheduler_.post_deferred_completion(op); + } + } + else + { + op->ec_ = asio::error::bad_descriptor; + scheduler_.post_deferred_completion(op); + } +} + +void win_object_handle_service::register_wait_callback( + win_object_handle_service::implementation_type& impl, + mutex::scoped_lock& lock) +{ + lock.lock(); + + if (!RegisterWaitForSingleObject(&impl.wait_handle_, + impl.handle_, &win_object_handle_service::wait_callback, + &impl, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = ec; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + lock.unlock(); + scheduler_.post_deferred_completions(completed_ops); + } +} + +void win_object_handle_service::wait_callback(PVOID param, BOOLEAN) +{ + implementation_type* impl = static_cast(param); + mutex::scoped_lock lock(impl->owner_->mutex_); + + if (impl->wait_handle_ != INVALID_HANDLE_VALUE) + { + ::UnregisterWaitEx(impl->wait_handle_, NULL); + impl->wait_handle_ = INVALID_HANDLE_VALUE; + } + + if (wait_op* op = impl->op_queue_.front()) + { + op_queue completed_ops; + + op->ec_ = asio::error_code(); + impl->op_queue_.pop(); + completed_ops.push(op); + + if (!impl->op_queue_.empty()) + { + if (!RegisterWaitForSingleObject(&impl->wait_handle_, + impl->handle_, &win_object_handle_service::wait_callback, + param, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + + while ((op = impl->op_queue_.front()) != 0) + { + op->ec_ = ec; + impl->op_queue_.pop(); + completed_ops.push(op); + } + } + } + + scheduler_impl& sched = impl->owner_->scheduler_; + lock.unlock(); + sched.post_deferred_completions(completed_ops); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_static_mutex.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_static_mutex.ipp new file mode 100644 index 0000000..070eb59 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_static_mutex.ipp @@ -0,0 +1,136 @@ +// +// detail/impl/win_static_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP +#define ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_static_mutex.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void win_static_mutex::init() +{ + int error = do_init(); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "static_mutex"); +} + +int win_static_mutex::do_init() +{ + using namespace std; // For sprintf. + wchar_t mutex_name[128]; +#if defined(ASIO_HAS_SECURE_RTL) + swprintf_s( +#else // defined(ASIO_HAS_SECURE_RTL) + _snwprintf( +#endif // defined(ASIO_HAS_SECURE_RTL) + mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p", + static_cast(::GetCurrentProcessId()), this); + +#if defined(ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0); +#else // defined(ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name); +#endif // defined(ASIO_WINDOWS_APP) + DWORD last_error = ::GetLastError(); + if (mutex == 0) + return ::GetLastError(); + + if (last_error == ERROR_ALREADY_EXISTS) + { +#if defined(ASIO_WINDOWS_APP) + ::WaitForSingleObjectEx(mutex, INFINITE, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForSingleObject(mutex, INFINITE); +#endif // defined(ASIO_WINDOWS_APP) + } + + if (initialised_) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; + } + +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return ERROR_OUTOFMEMORY; + } +#endif + + initialised_ = true; + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_thread.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_thread.ipp new file mode 100644 index 0000000..142ba67 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_thread.ipp @@ -0,0 +1,150 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_THREAD_IPP +#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_thread.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_thread::~win_thread() +{ + ::CloseHandle(thread_); + + // The exit_event_ handle is deliberately allowed to leak here since it + // is an error for the owner of an internal thread not to join() it. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +std::size_t win_thread::hardware_concurrency() +{ + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + win_thread::auto_func_base_ptr func = { + static_cast(arg) }; + + ::SetEvent(func.ptr->entry_event_); + + func.ptr->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func.ptr->exit_event_; + delete func.ptr; + func.ptr = 0; + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/win_tss_ptr.ipp b/extern/asio-1.18.2/include/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 0000000..c6ece2e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,57 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_tss_ptr.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + const DWORD out_of_indexes = 0xFFFFFFFF; +#else + const DWORD out_of_indexes = TLS_OUT_OF_INDEXES; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/winrt_ssocket_service_base.ipp b/extern/asio-1.18.2/include/asio/detail/impl/winrt_ssocket_service_base.ipp new file mode 100644 index 0000000..92a29f0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/winrt_ssocket_service_base.ipp @@ -0,0 +1,626 @@ +// +// detail/impl/winrt_ssocket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include +#include "asio/detail/winrt_ssocket_service_base.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/detail/winrt_utils.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +winrt_ssocket_service_base::winrt_ssocket_service_base( + execution_context& context) + : scheduler_(use_service(context)), + async_manager_(use_service(context)), + mutex_(), + impl_list_(0) +{ +} + +void winrt_ssocket_service_base::base_shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + asio::error_code ignored_ec; + close(*impl, ignored_ec); + impl = impl->next_; + } +} + +void winrt_ssocket_service_base::construct( + winrt_ssocket_service_base::base_implementation_type& impl) +{ + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void winrt_ssocket_service_base::base_move_construct( + winrt_ssocket_service_base::base_implementation_type& impl, + winrt_ssocket_service_base::base_implementation_type& other_impl) + ASIO_NOEXCEPT +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = nullptr; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void winrt_ssocket_service_base::base_move_assign( + winrt_ssocket_service_base::base_implementation_type& impl, + winrt_ssocket_service_base& other_service, + winrt_ssocket_service_base::base_implementation_type& other_impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = nullptr; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void winrt_ssocket_service_base::destroy( + winrt_ssocket_service_base::base_implementation_type& impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code winrt_ssocket_service_base::close( + winrt_ssocket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + delete impl.socket_; + impl.socket_ = nullptr; + ec = asio::error_code(); + return ec; +} + +winrt_ssocket_service_base::native_handle_type +winrt_ssocket_service_base::release( + winrt_ssocket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return nullptr; + + cancel(impl, ec); + if (ec) + return nullptr; + + native_handle_type tmp = impl.socket_; + impl.socket_ = nullptr; + return tmp; +} + +std::size_t winrt_ssocket_service_base::do_get_endpoint( + const base_implementation_type& impl, bool local, + void* addr, std::size_t addr_len, asio::error_code& ec) const +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return addr_len; + } + + try + { + std::string addr_string = winrt_utils::string(local + ? impl.socket_->Information->LocalAddress->CanonicalName + : impl.socket_->Information->RemoteAddress->CanonicalName); + unsigned short port = winrt_utils::integer(local + ? impl.socket_->Information->LocalPort + : impl.socket_->Information->RemotePort); + unsigned long scope = 0; + + switch (reinterpret_cast(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + if (addr_len < sizeof(sockaddr_in4_type)) + { + ec = asio::error::invalid_argument; + return addr_len; + } + else + { + socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(), + &reinterpret_cast(addr)->sin_addr, &scope, ec); + reinterpret_cast(addr)->sin_port + = socket_ops::host_to_network_short(port); + ec = asio::error_code(); + return sizeof(sockaddr_in4_type); + } + case ASIO_OS_DEF(AF_INET6): + if (addr_len < sizeof(sockaddr_in6_type)) + { + ec = asio::error::invalid_argument; + return addr_len; + } + else + { + socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(), + &reinterpret_cast(addr)->sin6_addr, &scope, ec); + reinterpret_cast(addr)->sin6_port + = socket_ops::host_to_network_short(port); + ec = asio::error_code(); + return sizeof(sockaddr_in6_type); + } + default: + ec = asio::error::address_family_not_supported; + return addr_len; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return addr_len; + } +} + +asio::error_code winrt_ssocket_service_base::do_set_option( + winrt_ssocket_service_base::base_implementation_type& impl, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + try + { + if (level == ASIO_OS_DEF(SOL_SOCKET) + && optname == ASIO_OS_DEF(SO_KEEPALIVE)) + { + if (optlen == sizeof(int)) + { + int value = 0; + std::memcpy(&value, optval, optlen); + impl.socket_->Control->KeepAlive = !!value; + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else if (level == ASIO_OS_DEF(IPPROTO_TCP) + && optname == ASIO_OS_DEF(TCP_NODELAY)) + { + if (optlen == sizeof(int)) + { + int value = 0; + std::memcpy(&value, optval, optlen); + impl.socket_->Control->NoDelay = !!value; + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else + { + ec = asio::error::invalid_argument; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; +} + +void winrt_ssocket_service_base::do_get_option( + const winrt_ssocket_service_base::base_implementation_type& impl, + int level, int optname, void* optval, + std::size_t* optlen, asio::error_code& ec) const +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return; + } + + try + { + if (level == ASIO_OS_DEF(SOL_SOCKET) + && optname == ASIO_OS_DEF(SO_KEEPALIVE)) + { + if (*optlen >= sizeof(int)) + { + int value = impl.socket_->Control->KeepAlive ? 1 : 0; + std::memcpy(optval, &value, sizeof(int)); + *optlen = sizeof(int); + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else if (level == ASIO_OS_DEF(IPPROTO_TCP) + && optname == ASIO_OS_DEF(TCP_NODELAY)) + { + if (*optlen >= sizeof(int)) + { + int value = impl.socket_->Control->NoDelay ? 1 : 0; + std::memcpy(optval, &value, sizeof(int)); + *optlen = sizeof(int); + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else + { + ec = asio::error::invalid_argument; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } +} + +asio::error_code winrt_ssocket_service_base::do_connect( + winrt_ssocket_service_base::base_implementation_type& impl, + const void* addr, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + char addr_string[max_addr_v6_str_len]; + unsigned short port; + switch (reinterpret_cast(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), + &reinterpret_cast(addr)->sin_addr, + addr_string, sizeof(addr_string), 0, ec); + port = socket_ops::network_to_host_short( + reinterpret_cast(addr)->sin_port); + break; + case ASIO_OS_DEF(AF_INET6): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6), + &reinterpret_cast(addr)->sin6_addr, + addr_string, sizeof(addr_string), 0, ec); + port = socket_ops::network_to_host_short( + reinterpret_cast(addr)->sin6_port); + break; + default: + ec = asio::error::address_family_not_supported; + return ec; + } + + if (!ec) try + { + async_manager_.sync(impl.socket_->ConnectAsync( + ref new Windows::Networking::HostName( + winrt_utils::string(addr_string)), + winrt_utils::string(port)), ec); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; +} + +void winrt_ssocket_service_base::start_connect_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const void* addr, winrt_async_op* op, bool is_continuation) +{ + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + char addr_string[max_addr_v6_str_len]; + unsigned short port = 0; + switch (reinterpret_cast(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), + &reinterpret_cast(addr)->sin_addr, + addr_string, sizeof(addr_string), 0, op->ec_); + port = socket_ops::network_to_host_short( + reinterpret_cast(addr)->sin_port); + break; + case ASIO_OS_DEF(AF_INET6): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6), + &reinterpret_cast(addr)->sin6_addr, + addr_string, sizeof(addr_string), 0, op->ec_); + port = socket_ops::network_to_host_short( + reinterpret_cast(addr)->sin6_port); + break; + default: + op->ec_ = asio::error::address_family_not_supported; + break; + } + + if (op->ec_) + { + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + async_manager_.async(impl.socket_->ConnectAsync( + ref new Windows::Networking::HostName( + winrt_utils::string(addr_string)), + winrt_utils::string(port)), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code( + e->HResult, asio::system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + } +} + +std::size_t winrt_ssocket_service_base::do_send( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::const_buffer& data, + socket_base::message_flags flags, asio::error_code& ec) +{ + if (flags) + { + ec = asio::error::operation_not_supported; + return 0; + } + + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + try + { + buffer_sequence_adapter bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + ec = asio::error_code(); + return 0; + } + + return async_manager_.sync( + impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return 0; + } +} + +void winrt_ssocket_service_base::start_send_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::const_buffer& data, socket_base::message_flags flags, + winrt_async_op* op, bool is_continuation) +{ + if (flags) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + buffer_sequence_adapter bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + async_manager_.async( + impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code(e->HResult, + asio::system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + } +} + +std::size_t winrt_ssocket_service_base::do_receive( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::mutable_buffer& data, + socket_base::message_flags flags, asio::error_code& ec) +{ + if (flags) + { + ec = asio::error::operation_not_supported; + return 0; + } + + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + try + { + buffer_sequence_adapter bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + ec = asio::error_code(); + return 0; + } + + async_manager_.sync( + impl.socket_->InputStream->ReadAsync( + bufs.buffers()[0], bufs.buffers()[0]->Capacity, + Windows::Storage::Streams::InputStreamOptions::Partial), ec); + + std::size_t bytes_transferred = bufs.buffers()[0]->Length; + if (bytes_transferred == 0 && !ec) + { + ec = asio::error::eof; + } + + return bytes_transferred; + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return 0; + } +} + +void winrt_ssocket_service_base::start_receive_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::mutable_buffer& data, socket_base::message_flags flags, + winrt_async_op* op, + bool is_continuation) +{ + if (flags) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + buffer_sequence_adapter bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + async_manager_.async( + impl.socket_->InputStream->ReadAsync( + bufs.buffers()[0], bufs.buffers()[0]->Capacity, + Windows::Storage::Streams::InputStreamOptions::Partial), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code(e->HResult, + asio::system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.hpp b/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..7c7da52 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.hpp @@ -0,0 +1,92 @@ +// +// detail/impl/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +void winrt_timer_scheduler::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void winrt_timer_scheduler::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void winrt_timer_scheduler::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + event_.signal(lock); +} + +template +std::size_t winrt_timer_scheduler::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void winrt_timer_scheduler::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.ipp b/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.ipp new file mode 100644 index 0000000..d3d6103 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/winrt_timer_scheduler.ipp @@ -0,0 +1,121 @@ +// +// detail/impl/winrt_timer_scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP +#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/winrt_timer_scheduler.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context) + : execution_context_service_base(context), + scheduler_(use_service(context)), + mutex_(), + event_(), + timer_queues_(), + thread_(0), + stop_thread_(false), + shutdown_(false) +{ + thread_ = new asio::detail::thread( + bind_handler(&winrt_timer_scheduler::call_run_thread, this)); +} + +winrt_timer_scheduler::~winrt_timer_scheduler() +{ + shutdown(); +} + +void winrt_timer_scheduler::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + event_.signal(lock); + lock.unlock(); + + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + + op_queue ops; + timer_queues_.get_all_timers(ops); + scheduler_.abandon_operations(ops); +} + +void winrt_timer_scheduler::notify_fork(execution_context::fork_event) +{ +} + +void winrt_timer_scheduler::init_task() +{ +} + +void winrt_timer_scheduler::run_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + const long max_wait_duration = 5 * 60 * 1000000; + long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration); + event_.wait_for_usec(lock, wait_duration); + event_.clear(lock); + op_queue ops; + timer_queues_.get_ready_timers(ops); + if (!ops.empty()) + { + lock.unlock(); + scheduler_.post_deferred_completions(ops); + lock.lock(); + } + } +} + +void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler) +{ + scheduler->run_thread(); +} + +void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/impl/winsock_init.ipp b/extern/asio-1.18.2/include/asio/detail/impl/winsock_init.ipp new file mode 100644 index 0000000..f2e8cb5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,82 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP +#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::manual_startup(data& d) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + ::InterlockedExchange(&d.result_, 0); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::manual_cleanup(data& d) +{ + ::InterlockedDecrement(&d.init_count_); +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + asio::error_code ec(result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/extern/asio-1.18.2/include/asio/detail/io_control.hpp b/extern/asio-1.18.2/include/asio/detail/io_control.hpp new file mode 100644 index 0000000..2b6d593 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/io_control.hpp @@ -0,0 +1,84 @@ +// +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IO_CONTROL_HPP +#define ASIO_DETAIL_IO_CONTROL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace io_control { + +// I/O control command for getting number of bytes available. +class bytes_readable +{ +public: + // Default constructor. + bytes_readable() + : value_(0) + { + } + + // Construct with a specific command value. + bytes_readable(std::size_t value) + : value_(static_cast(value)) + { + } + + // Get the name of the IO control command. + int name() const + { + return static_cast(ASIO_OS_DEF(FIONREAD)); + } + + // Set the value of the I/O control command. + void set(std::size_t value) + { + value_ = static_cast(value); + } + + // Get the current value of the I/O control command. + std::size_t get() const + { + return static_cast(value_); + } + + // Get the address of the command data. + detail::ioctl_arg_type* data() + { + return &value_; + } + + // Get the address of the command data. + const detail::ioctl_arg_type* data() const + { + return &value_; + } + +private: + detail::ioctl_arg_type value_; +}; + +} // namespace io_control +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_CONTROL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/io_object_impl.hpp b/extern/asio-1.18.2/include/asio/detail/io_object_impl.hpp new file mode 100644 index 0000000..9efd0d6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/io_object_impl.hpp @@ -0,0 +1,172 @@ +// +// io_object_impl.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IO_OBJECT_IMPL_HPP +#define ASIO_DETAIL_IO_OBJECT_IMPL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/context.hpp" +#include "asio/io_context.hpp" +#include "asio/query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class io_object_impl +{ +public: + // The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + // The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + + // The type of the executor associated with the object. + typedef Executor executor_type; + + // Construct an I/O object using an executor. + explicit io_object_impl(int, const executor_type& ex) + : service_(&asio::use_service( + io_object_impl::get_context(ex))), + executor_(ex) + { + service_->construct(implementation_); + } + + // Construct an I/O object using an execution context. + template + explicit io_object_impl(int, int, ExecutionContext& context) + : service_(&asio::use_service(context)), + executor_(context.get_executor()) + { + service_->construct(implementation_); + } + +#if defined(ASIO_HAS_MOVE) + // Move-construct an I/O object. + io_object_impl(io_object_impl&& other) + : service_(&other.get_service()), + executor_(other.get_executor()) + { + service_->move_construct(implementation_, other.implementation_); + } + + // Perform a converting move-construction of an I/O object. + template + io_object_impl(io_object_impl&& other) + : service_(&asio::use_service( + io_object_impl::get_context(other.get_executor()))), + executor_(other.get_executor()) + { + service_->converting_move_construct(implementation_, + other.get_service(), other.get_implementation()); + } +#endif // defined(ASIO_HAS_MOVE) + + // Destructor. + ~io_object_impl() + { + service_->destroy(implementation_); + } + +#if defined(ASIO_HAS_MOVE) + // Move-assign an I/O object. + io_object_impl& operator=(io_object_impl&& other) + { + if (this != &other) + { + service_->move_assign(implementation_, + *other.service_, other.implementation_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } +#endif // defined(ASIO_HAS_MOVE) + + // Get the executor associated with the object. + const executor_type& get_executor() ASIO_NOEXCEPT + { + return executor_; + } + + // Get the service associated with the I/O object. + service_type& get_service() + { + return *service_; + } + + // Get the service associated with the I/O object. + const service_type& get_service() const + { + return *service_; + } + + // Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation_; + } + + // Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + // Helper function to get an executor's context. + template + static execution_context& get_context(const T& t, + typename enable_if::value>::type* = 0) + { + return asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template + static execution_context& get_context(const T& t, + typename enable_if::value>::type* = 0) + { + return t.context(); + } + + // Disallow copying and copy assignment. + io_object_impl(const io_object_impl&); + io_object_impl& operator=(const io_object_impl&); + + // The service associated with the I/O object. + service_type* service_; + + // The underlying implementation of the I/O object. + implementation_type implementation_; + + // The associated executor. + executor_type executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_OBJECT_IMPL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/is_buffer_sequence.hpp b/extern/asio-1.18.2/include/asio/detail/is_buffer_sequence.hpp new file mode 100644 index 0000000..e3d8de3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/is_buffer_sequence.hpp @@ -0,0 +1,312 @@ +// +// detail/is_buffer_sequence.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP +#define ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class mutable_buffer; +class const_buffer; + +namespace detail { + +struct buffer_sequence_memfns_base +{ + void begin(); + void end(); + void size(); + void max_size(); + void capacity(); + void data(); + void prepare(); + void commit(); + void consume(); + void grow(); + void shrink(); +}; + +template +struct buffer_sequence_memfns_derived + : T, buffer_sequence_memfns_base +{ +}; + +template +struct buffer_sequence_memfns_check +{ +}; + +#if defined(ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_begin_helper(...); + +template +char (&buffer_sequence_begin_helper(T* t, + typename enable_if::value>::type*))[2]; + +#else // defined(ASIO_HAS_DECLTYPE) + +template +char (&buffer_sequence_begin_helper(...))[2]; + +template +char buffer_sequence_begin_helper(T* t, + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::begin>*); + +#endif // defined(ASIO_HAS_DECLTYPE) + +#if defined(ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_end_helper(...); + +template +char (&buffer_sequence_end_helper(T* t, + typename enable_if::value>::type*))[2]; + +#else // defined(ASIO_HAS_DECLTYPE) + +template +char (&buffer_sequence_end_helper(...))[2]; + +template +char buffer_sequence_end_helper(T* t, + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::end>*); + +#endif // defined(ASIO_HAS_DECLTYPE) + +template +char (&size_memfn_helper(...))[2]; + +template +char size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::size>*); + +template +char (&max_size_memfn_helper(...))[2]; + +template +char max_size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::max_size>*); + +template +char (&capacity_memfn_helper(...))[2]; + +template +char capacity_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::capacity>*); + +template +char (&data_memfn_helper(...))[2]; + +template +char data_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::data>*); + +template +char (&prepare_memfn_helper(...))[2]; + +template +char prepare_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::prepare>*); + +template +char (&commit_memfn_helper(...))[2]; + +template +char commit_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::commit>*); + +template +char (&consume_memfn_helper(...))[2]; + +template +char consume_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::consume>*); + +template +char (&grow_memfn_helper(...))[2]; + +template +char grow_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::grow>*); + +template +char (&shrink_memfn_helper(...))[2]; + +template +char shrink_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::shrink>*); + +template +char (&buffer_sequence_element_type_helper(...))[2]; + +#if defined(ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_element_type_helper(T* t, + typename enable_if::value>::type*); + +#else // defined(ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_element_type_helper( + typename T::const_iterator*, + typename enable_if::value>::type*); + +#endif // defined(ASIO_HAS_DECLTYPE) + +template +char (&const_buffers_type_typedef_helper(...))[2]; + +template +char const_buffers_type_typedef_helper( + typename T::const_buffers_type*); + +template +char (&mutable_buffers_type_typedef_helper(...))[2]; + +template +char mutable_buffers_type_typedef_helper( + typename T::mutable_buffers_type*); + +template +struct is_buffer_sequence_class + : integral_constant(0, 0)) != 1 && + sizeof(buffer_sequence_end_helper(0, 0)) != 1 && + sizeof(buffer_sequence_element_type_helper(0, 0)) == 1> +{ +}; + +template +struct is_buffer_sequence + : conditional::value, + is_buffer_sequence_class, + false_type>::type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : false_type +{ +}; + +template +struct is_dynamic_buffer_class_v1 + : integral_constant(0)) != 1 && + sizeof(max_size_memfn_helper(0)) != 1 && + sizeof(capacity_memfn_helper(0)) != 1 && + sizeof(data_memfn_helper(0)) != 1 && + sizeof(consume_memfn_helper(0)) != 1 && + sizeof(prepare_memfn_helper(0)) != 1 && + sizeof(commit_memfn_helper(0)) != 1 && + sizeof(const_buffers_type_typedef_helper(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper(0)) == 1> +{ +}; + +template +struct is_dynamic_buffer_v1 + : conditional::value, + is_dynamic_buffer_class_v1, + false_type>::type +{ +}; + +template +struct is_dynamic_buffer_class_v2 + : integral_constant(0)) != 1 && + sizeof(max_size_memfn_helper(0)) != 1 && + sizeof(capacity_memfn_helper(0)) != 1 && + sizeof(data_memfn_helper(0)) != 1 && + sizeof(consume_memfn_helper(0)) != 1 && + sizeof(grow_memfn_helper(0)) != 1 && + sizeof(shrink_memfn_helper(0)) != 1 && + sizeof(const_buffers_type_typedef_helper(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper(0)) == 1> +{ +}; + +template +struct is_dynamic_buffer_v2 + : conditional::value, + is_dynamic_buffer_class_v2, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/is_executor.hpp b/extern/asio-1.18.2/include/asio/detail/is_executor.hpp new file mode 100644 index 0000000..a099eec --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/is_executor.hpp @@ -0,0 +1,126 @@ +// +// detail/is_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_IS_EXECUTOR_HPP +#define ASIO_DETAIL_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct executor_memfns_base +{ + void context(); + void on_work_started(); + void on_work_finished(); + void dispatch(); + void post(); + void defer(); +}; + +template +struct executor_memfns_derived + : T, executor_memfns_base +{ +}; + +template +struct executor_memfns_check +{ +}; + +template +char (&context_memfn_helper(...))[2]; + +template +char context_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::context>*); + +template +char (&on_work_started_memfn_helper(...))[2]; + +template +char on_work_started_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::on_work_started>*); + +template +char (&on_work_finished_memfn_helper(...))[2]; + +template +char on_work_finished_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::on_work_finished>*); + +template +char (&dispatch_memfn_helper(...))[2]; + +template +char dispatch_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::dispatch>*); + +template +char (&post_memfn_helper(...))[2]; + +template +char post_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::post>*); + +template +char (&defer_memfn_helper(...))[2]; + +template +char defer_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::defer>*); + +template +struct is_executor_class + : integral_constant(0)) != 1 && + sizeof(on_work_started_memfn_helper(0)) != 1 && + sizeof(on_work_finished_memfn_helper(0)) != 1 && + sizeof(dispatch_memfn_helper(0)) != 1 && + sizeof(post_memfn_helper(0)) != 1 && + sizeof(defer_memfn_helper(0)) != 1> +{ +}; + +template +struct is_executor + : conditional::value, + is_executor_class, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IS_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/keyword_tss_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/keyword_tss_ptr.hpp new file mode 100644 index 0000000..9378af3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/keyword_tss_ptr.hpp @@ -0,0 +1,70 @@ +// +// detail/keyword_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_KEYWORD_TSS_PTR_HPP +#define ASIO_DETAIL_KEYWORD_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class keyword_tss_ptr + : private noncopyable +{ +public: + // Constructor. + keyword_tss_ptr() + { + } + + // Destructor. + ~keyword_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + static ASIO_THREAD_KEYWORD T* value_; +}; + +template +ASIO_THREAD_KEYWORD T* keyword_tss_ptr::value_; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#endif // ASIO_DETAIL_KEYWORD_TSS_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/kqueue_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/kqueue_reactor.hpp new file mode 100644 index 0000000..97e6706 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/kqueue_reactor.hpp @@ -0,0 +1,242 @@ +// +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_KQUEUE_REACTOR_HPP +#define ASIO_DETAIL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include +#include +#include +#include +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/object_pool.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +// Older versions of Mac OS X may not define EV_OOBAND. +#if !defined(EV_OOBAND) +# define EV_OOBAND EV_FLAG1 +#endif // !defined(EV_OOBAND) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; + +class kqueue_reactor + : public execution_context_service_base +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state + { + descriptor_state(bool locking) : mutex_(locking) {} + + friend class kqueue_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + int descriptor_; + int num_kevents_; // 1 == read only, 2 == read and write + op_queue op_queue_[max_ops]; + bool shutdown_; + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + ASIO_DECL kqueue_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~kqueue_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run the kqueue loop. + ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the kqueue loop. + ASIO_DECL void interrupt(); + +private: + // Create the kqueue file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_kqueue_create(); + + // Allocate a new descriptor state object. + ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the kevent call. + ASIO_DECL timespec* get_timeout(long usec, timespec& ts); + + // The scheduler used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The kqueue file descriptor. + int kqueue_fd_; + + // The interrupter is used to break a blocking kevent call. + select_interrupter interrupter_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool registered_descriptors_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/kqueue_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/kqueue_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/limits.hpp b/extern/asio-1.18.2/include/asio/detail/limits.hpp new file mode 100644 index 0000000..d32470d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/limits.hpp @@ -0,0 +1,26 @@ +// +// detail/limits.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 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 ASIO_DETAIL_LIMITS_HPP +#define ASIO_DETAIL_LIMITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_LIMITS) +# include +#else // defined(ASIO_HAS_BOOST_LIMITS) +# include +#endif // defined(ASIO_HAS_BOOST_LIMITS) + +#endif // ASIO_DETAIL_LIMITS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/local_free_on_block_exit.hpp b/extern/asio-1.18.2/include/asio/detail/local_free_on_block_exit.hpp new file mode 100644 index 0000000..9ca4b3f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/local_free_on_block_exit.hpp @@ -0,0 +1,59 @@ +// +// detail/local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if !defined(ASIO_WINDOWS_APP) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class local_free_on_block_exit + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + explicit local_free_on_block_exit(void* p) + : p_(p) + { + } + + // Destructor restores the previous signal mask. + ~local_free_on_block_exit() + { + ::LocalFree(p_); + } + +private: + void* p_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS_APP) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/macos_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/macos_fenced_block.hpp new file mode 100644 index 0000000..54768e5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/macos_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP +#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__MACH__) && defined(__APPLE__) + +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class macos_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit macos_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit macos_fenced_block(full_t) + { + OSMemoryBarrier(); + } + + // Destructor. + ~macos_fenced_block() + { + OSMemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__MACH__) && defined(__APPLE__) + +#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/memory.hpp b/extern/asio-1.18.2/include/asio/detail/memory.hpp new file mode 100644 index 0000000..2afb43e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/memory.hpp @@ -0,0 +1,73 @@ +// +// detail/memory.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_MEMORY_HPP +#define ASIO_DETAIL_MEMORY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include + +#if !defined(ASIO_HAS_STD_SHARED_PTR) +# include +# include +# include +#endif // !defined(ASIO_HAS_STD_SHARED_PTR) + +#if !defined(ASIO_HAS_STD_ADDRESSOF) +# include +#endif // !defined(ASIO_HAS_STD_ADDRESSOF) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_SHARED_PTR) +using std::make_shared; +using std::shared_ptr; +using std::weak_ptr; +#else // defined(ASIO_HAS_STD_SHARED_PTR) +using boost::make_shared; +using boost::shared_ptr; +using boost::weak_ptr; +#endif // defined(ASIO_HAS_STD_SHARED_PTR) + +#if defined(ASIO_HAS_STD_ADDRESSOF) +using std::addressof; +#else // defined(ASIO_HAS_STD_ADDRESSOF) +using boost::addressof; +#endif // defined(ASIO_HAS_STD_ADDRESSOF) + +} // namespace detail + +#if defined(ASIO_HAS_CXX11_ALLOCATORS) +using std::allocator_arg_t; +# define ASIO_USES_ALLOCATOR(t) \ + namespace std { \ + template \ + struct uses_allocator : true_type {}; \ + } \ + /**/ +# define ASIO_REBIND_ALLOC(alloc, t) \ + typename std::allocator_traits::template rebind_alloc + /**/ +#else // defined(ASIO_HAS_CXX11_ALLOCATORS) +struct allocator_arg_t {}; +# define ASIO_USES_ALLOCATOR(t) +# define ASIO_REBIND_ALLOC(alloc, t) \ + typename alloc::template rebind::other + /**/ +#endif // defined(ASIO_HAS_CXX11_ALLOCATORS) + +} // namespace asio + +#endif // ASIO_DETAIL_MEMORY_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/mutex.hpp b/extern/asio-1.18.2/include/asio/detail/mutex.hpp new file mode 100644 index 0000000..283fade --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/mutex.hpp @@ -0,0 +1,48 @@ +// +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_MUTEX_HPP +#define ASIO_DETAIL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_mutex.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_mutex.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_mutex.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_mutex.hpp" +#else +# error Only Windows, POSIX and std::mutex are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_mutex mutex; +#elif defined(ASIO_WINDOWS) +typedef win_mutex mutex; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_mutex mutex; +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_mutex mutex; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/non_const_lvalue.hpp b/extern/asio-1.18.2/include/asio/detail/non_const_lvalue.hpp new file mode 100644 index 0000000..4960365 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/non_const_lvalue.hpp @@ -0,0 +1,54 @@ +// +// detail/non_const_lvalue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NON_CONST_LVALUE_HPP +#define ASIO_DETAIL_NON_CONST_LVALUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct non_const_lvalue +{ +#if defined(ASIO_HAS_MOVE) + explicit non_const_lvalue(T& t) + : value(static_cast::type>::value, + typename decay::type&, T&&>::type>(t)) + { + } + + typename conditional::type>::value, + typename decay::type&, typename decay::type>::type value; +#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + explicit non_const_lvalue(const typename decay::type& t) + : value(t) + { + } + + typename decay::type value; +#endif // defined(ASIO_HAS_MOVE) +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NON_CONST_LVALUE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/noncopyable.hpp b/extern/asio-1.18.2/include/asio/detail/noncopyable.hpp new file mode 100644 index 0000000..a148e03 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/noncopyable.hpp @@ -0,0 +1,43 @@ +// +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NONCOPYABLE_HPP +#define ASIO_DETAIL_NONCOPYABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class noncopyable +{ +protected: + noncopyable() {} + ~noncopyable() {} +private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); +}; + +} // namespace detail + +using asio::detail::noncopyable; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NONCOPYABLE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_event.hpp b/extern/asio-1.18.2/include/asio/detail/null_event.hpp new file mode 100644 index 0000000..5bff3c4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_event.hpp @@ -0,0 +1,106 @@ +// +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_EVENT_HPP +#define ASIO_DETAIL_NULL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_event + : private noncopyable +{ +public: + // Constructor. + null_event() + { + } + + // Destructor. + ~null_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock&) + { + } + + // Signal all waiters. + template + void signal_all(Lock&) + { + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock&) + { + } + + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock&) + { + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock&) + { + return false; + } + + // Reset the event. + template + void clear(Lock&) + { + } + + // Wait for the event to become signalled. + template + void wait(Lock&) + { + do_wait(); + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock&, long usec) + { + do_wait_for_usec(usec); + return true; + } + +private: + ASIO_DECL static void do_wait(); + ASIO_DECL static void do_wait_for_usec(long usec); +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/null_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_NULL_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/null_fenced_block.hpp new file mode 100644 index 0000000..265b3bf --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_fenced_block.hpp @@ -0,0 +1,47 @@ +// +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_FENCED_BLOCK_HPP +#define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit null_fenced_block(half_or_full_t) + { + } + + // Destructor. + ~null_fenced_block() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_global.hpp b/extern/asio-1.18.2/include/asio/detail/null_global.hpp new file mode 100644 index 0000000..7bd1250 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_global.hpp @@ -0,0 +1,59 @@ +// +// detail/null_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_GLOBAL_HPP +#define ASIO_DETAIL_NULL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct null_global_impl +{ + null_global_impl() + : ptr_(0) + { + } + + // Destructor automatically cleans up the global. + ~null_global_impl() + { + delete ptr_; + } + + static null_global_impl instance_; + T* ptr_; +}; + +template +null_global_impl null_global_impl::instance_; + +template +T& null_global() +{ + if (null_global_impl::instance_.ptr_ == 0) + null_global_impl::instance_.ptr_ = new T; + return *null_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NULL_GLOBAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/null_mutex.hpp new file mode 100644 index 0000000..b545733 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_mutex.hpp @@ -0,0 +1,64 @@ +// +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_MUTEX_HPP +#define ASIO_DETAIL_NULL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock scoped_lock; + + // Constructor. + null_mutex() + { + } + + // Destructor. + ~null_mutex() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/null_reactor.hpp new file mode 100644 index 0000000..f05c6ee --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_reactor.hpp @@ -0,0 +1,68 @@ +// +// detail/null_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_REACTOR_HPP +#define ASIO_DETAIL_NULL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/scheduler_operation.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_reactor + : public execution_context_service_base +{ +public: + // Constructor. + null_reactor(asio::execution_context& ctx) + : execution_context_service_base(ctx) + { + } + + // Destructor. + ~null_reactor() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // No-op because should never be called. + void run(long /*usec*/, op_queue& /*ops*/) + { + } + + // No-op. + void interrupt() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_NULL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_signal_blocker.hpp b/extern/asio-1.18.2/include/asio/detail/null_signal_blocker.hpp new file mode 100644 index 0000000..8a9bf36 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_signal_blocker.hpp @@ -0,0 +1,69 @@ +// +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + null_signal_blocker() + { + } + + // Destructor restores the previous signal mask. + ~null_signal_blocker() + { + } + + // Block all signals for the calling thread. + void block() + { + } + + // Restore the previous signal mask. + void unblock() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + // || defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_socket_service.hpp b/extern/asio-1.18.2/include/asio/detail/null_socket_service.hpp new file mode 100644 index 0000000..e652546 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_socket_service.hpp @@ -0,0 +1,519 @@ +// +// detail/null_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/post.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class null_socket_service : + public execution_context_service_base > +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef int native_handle_type; + + // The implementation type of the socket. + struct implementation_type + { + }; + + // Constructor. + null_socket_service(execution_context& context) + : execution_context_service_base >(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new socket implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type&, implementation_type&) + { + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type&, + null_socket_service&, implementation_type&) + { + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type&, + null_socket_service&, + typename null_socket_service::implementation_type&) + { + } + + // Destroy a socket implementation. + void destroy(implementation_type&) + { + } + + // Open a new socket implementation. + asio::error_code open(implementation_type&, + const protocol_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type&, const protocol_type&, + const native_handle_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is open. + bool is_open(const implementation_type&) const + { + return false; + } + + // Destroy a socket implementation. + asio::error_code close(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Release ownership of the socket. + native_handle_type release(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type&) + { + return 0; + } + + // Cancel all operations associated with the socket. + asio::error_code cancel(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return false; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(implementation_type&, + int, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Perform an IO control command on the socket. + template + asio::error_code io_control(implementation_type&, + IO_Control_Command&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(implementation_type&, + socket_base::shutdown_type, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template + asio::error_code set_option(implementation_type&, + const Option&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template + asio::error_code get_option(const implementation_type&, + Option&, asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return endpoint_type(); + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return endpoint_type(); + } + + // Send the given data to the peer. + template + std::size_t send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send(implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive some data from the peer. Returns the number of bytes received. + template + std::size_t receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive(implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + std::size_t receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_with_flags(implementation_type&, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(implementation_type&, const null_buffers&, + socket_base::message_flags, socket_base::message_flags&, + Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + std::size_t send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + std::size_t receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Accept a new connection. + template + asio::error_code accept(implementation_type&, + Socket&, endpoint_type*, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type&, Socket&, endpoint_type*, + Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + asio::post(io_ex, detail::bind_handler(handler, ec)); + } + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + asio::post(io_ex, detail::bind_handler(handler, ec)); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_static_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/null_static_mutex.hpp new file mode 100644 index 0000000..4053056 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_static_mutex.hpp @@ -0,0 +1,60 @@ +// +// detail/null_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_STATIC_MUTEX_HPP +#define ASIO_DETAIL_NULL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct null_static_mutex +{ + typedef asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + void init() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } + + int unused_; +}; + +#define ASIO_NULL_STATIC_MUTEX_INIT { 0 } + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_STATIC_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_thread.hpp b/extern/asio-1.18.2/include/asio/detail/null_thread.hpp new file mode 100644 index 0000000..bbdba55 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_thread.hpp @@ -0,0 +1,67 @@ +// +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_THREAD_HPP +#define ASIO_DETAIL_NULL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_thread + : private noncopyable +{ +public: + // Constructor. + template + null_thread(Function, unsigned int = 0) + { + asio::detail::throw_error( + asio::error::operation_not_supported, "thread"); + } + + // Destructor. + ~null_thread() + { + } + + // Wait for the thread to exit. + void join() + { + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return 1; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/null_tss_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/null_tss_ptr.hpp new file mode 100644 index 0000000..e2b4cf3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/null_tss_ptr.hpp @@ -0,0 +1,68 @@ +// +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_NULL_TSS_PTR_HPP +#define ASIO_DETAIL_NULL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class null_tss_ptr + : private noncopyable +{ +public: + // Constructor. + null_tss_ptr() + : value_(0) + { + } + + // Destructor. + ~null_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + T* value_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/object_pool.hpp b/extern/asio-1.18.2/include/asio/detail/object_pool.hpp new file mode 100644 index 0000000..45524d3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/object_pool.hpp @@ -0,0 +1,171 @@ +// +// detail/object_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_OBJECT_POOL_HPP +#define ASIO_DETAIL_OBJECT_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class object_pool; + +class object_pool_access +{ +public: + template + static Object* create() + { + return new Object; + } + + template + static Object* create(Arg arg) + { + return new Object(arg); + } + + template + static void destroy(Object* o) + { + delete o; + } + + template + static Object*& next(Object* o) + { + return o->next_; + } + + template + static Object*& prev(Object* o) + { + return o->prev_; + } +}; + +template +class object_pool + : private noncopyable +{ +public: + // Constructor. + object_pool() + : live_list_(0), + free_list_(0) + { + } + + // Destructor destroys all objects. + ~object_pool() + { + destroy_list(live_list_); + destroy_list(free_list_); + } + + // Get the object at the start of the live list. + Object* first() + { + return live_list_; + } + + // Allocate a new object. + Object* alloc() + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create(); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Allocate a new object with an argument. + template + Object* alloc(Arg arg) + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create(arg); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Free an object. Moves it to the free list. No destructors are run. + void free(Object* o) + { + if (live_list_ == o) + live_list_ = object_pool_access::next(o); + + if (object_pool_access::prev(o)) + { + object_pool_access::next(object_pool_access::prev(o)) + = object_pool_access::next(o); + } + + if (object_pool_access::next(o)) + { + object_pool_access::prev(object_pool_access::next(o)) + = object_pool_access::prev(o); + } + + object_pool_access::next(o) = free_list_; + object_pool_access::prev(o) = 0; + free_list_ = o; + } + +private: + // Helper function to destroy all elements in a list. + void destroy_list(Object* list) + { + while (list) + { + Object* o = list; + list = object_pool_access::next(o); + object_pool_access::destroy(o); + } + } + + // The list of live objects. + Object* live_list_; + + // The free list. + Object* free_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_OBJECT_POOL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/old_win_sdk_compat.hpp b/extern/asio-1.18.2/include/asio/detail/old_win_sdk_compat.hpp new file mode 100644 index 0000000..734d72e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/old_win_sdk_compat.hpp @@ -0,0 +1,214 @@ +// +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP +#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Guess whether we are building against on old Platform SDK. +#if !defined(IN6ADDR_ANY_INIT) +#define ASIO_HAS_OLD_WIN_SDK 1 +#endif // !defined(IN6ADDR_ANY_INIT) + +#if defined(ASIO_HAS_OLD_WIN_SDK) + +// Emulation of types that are missing from old Platform SDKs. +// +// N.B. this emulation is also used if building for a Windows 2000 target with +// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support +// in that case. + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +enum +{ + sockaddr_storage_maxsize = 128, // Maximum size. + sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. + sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), + sockaddr_storage_pad2size = (sockaddr_storage_maxsize - + (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) +}; + +struct sockaddr_storage_emulation +{ + short ss_family; + char __ss_pad1[sockaddr_storage_pad1size]; + __int64 __ss_align; + char __ss_pad2[sockaddr_storage_pad2size]; +}; + +struct in6_addr_emulation +{ + union + { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#if !defined(s6_addr) +# define _S6_un u +# define _S6_u8 Byte +# define s6_addr _S6_un._S6_u8 +#endif // !defined(s6_addr) + +struct sockaddr_in6_emulation +{ + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + in6_addr_emulation sin6_addr; + u_long sin6_scope_id; +}; + +struct ipv6_mreq_emulation +{ + in6_addr_emulation ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +struct addrinfo_emulation +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo_emulation* ai_next; +}; + +#if !defined(AI_PASSIVE) +# define AI_PASSIVE 0x1 +#endif + +#if !defined(AI_CANONNAME) +# define AI_CANONNAME 0x2 +#endif + +#if !defined(AI_NUMERICHOST) +# define AI_NUMERICHOST 0x4 +#endif + +#if !defined(EAI_AGAIN) +# define EAI_AGAIN WSATRY_AGAIN +#endif + +#if !defined(EAI_BADFLAGS) +# define EAI_BADFLAGS WSAEINVAL +#endif + +#if !defined(EAI_FAIL) +# define EAI_FAIL WSANO_RECOVERY +#endif + +#if !defined(EAI_FAMILY) +# define EAI_FAMILY WSAEAFNOSUPPORT +#endif + +#if !defined(EAI_MEMORY) +# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY +#endif + +#if !defined(EAI_NODATA) +# define EAI_NODATA WSANO_DATA +#endif + +#if !defined(EAI_NONAME) +# define EAI_NONAME WSAHOST_NOT_FOUND +#endif + +#if !defined(EAI_SERVICE) +# define EAI_SERVICE WSATYPE_NOT_FOUND +#endif + +#if !defined(EAI_SOCKTYPE) +# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT +#endif + +#if !defined(NI_NOFQDN) +# define NI_NOFQDN 0x01 +#endif + +#if !defined(NI_NUMERICHOST) +# define NI_NUMERICHOST 0x02 +#endif + +#if !defined(NI_NAMEREQD) +# define NI_NAMEREQD 0x04 +#endif + +#if !defined(NI_NUMERICSERV) +# define NI_NUMERICSERV 0x08 +#endif + +#if !defined(NI_DGRAM) +# define NI_DGRAM 0x10 +#endif + +#if !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 +#endif + +#if !defined(IPV6_UNICAST_HOPS) +# define IPV6_UNICAST_HOPS 4 +#endif + +#if !defined(IPV6_MULTICAST_IF) +# define IPV6_MULTICAST_IF 9 +#endif + +#if !defined(IPV6_MULTICAST_HOPS) +# define IPV6_MULTICAST_HOPS 10 +#endif + +#if !defined(IPV6_MULTICAST_LOOP) +# define IPV6_MULTICAST_LOOP 11 +#endif + +#if !defined(IPV6_JOIN_GROUP) +# define IPV6_JOIN_GROUP 12 +#endif + +#if !defined(IPV6_LEAVE_GROUP) +# define IPV6_LEAVE_GROUP 13 +#endif + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_OLD_WIN_SDK) + +// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. +#if !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 27 +#endif + +// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. +#if !defined(IPPROTO_ICMPV6) +# define IPPROTO_ICMPV6 58 +#endif + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/op_queue.hpp b/extern/asio-1.18.2/include/asio/detail/op_queue.hpp new file mode 100644 index 0000000..1261339 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/op_queue.hpp @@ -0,0 +1,162 @@ +// +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_OP_QUEUE_HPP +#define ASIO_DETAIL_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class op_queue; + +class op_queue_access +{ +public: + template + static Operation* next(Operation* o) + { + return static_cast(o->next_); + } + + template + static void next(Operation1*& o1, Operation2* o2) + { + o1->next_ = o2; + } + + template + static void destroy(Operation* o) + { + o->destroy(); + } + + template + static Operation*& front(op_queue& q) + { + return q.front_; + } + + template + static Operation*& back(op_queue& q) + { + return q.back_; + } +}; + +template +class op_queue + : private noncopyable +{ +public: + // Constructor. + op_queue() + : front_(0), + back_(0) + { + } + + // Destructor destroys all operations. + ~op_queue() + { + while (Operation* op = front_) + { + pop(); + op_queue_access::destroy(op); + } + } + + // Get the operation at the front of the queue. + Operation* front() + { + return front_; + } + + // Pop an operation from the front of the queue. + void pop() + { + if (front_) + { + Operation* tmp = front_; + front_ = op_queue_access::next(front_); + if (front_ == 0) + back_ = 0; + op_queue_access::next(tmp, static_cast(0)); + } + } + + // Push an operation on to the back of the queue. + void push(Operation* h) + { + op_queue_access::next(h, static_cast(0)); + if (back_) + { + op_queue_access::next(back_, h); + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Push all operations from another queue on to the back of the queue. The + // source queue may contain operations of a derived type. + template + void push(op_queue& q) + { + if (Operation* other_front = op_queue_access::front(q)) + { + if (back_) + op_queue_access::next(back_, other_front); + else + front_ = other_front; + back_ = op_queue_access::back(q); + op_queue_access::front(q) = 0; + op_queue_access::back(q) = 0; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + + // Test whether an operation is already enqueued. + bool is_enqueued(Operation* o) const + { + return op_queue_access::next(o) != 0 || back_ == o; + } + +private: + friend class op_queue_access; + + // The front of the queue. + Operation* front_; + + // The back of the queue. + Operation* back_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_OP_QUEUE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/operation.hpp b/extern/asio-1.18.2/include/asio/detail/operation.hpp new file mode 100644 index 0000000..6e58117 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/operation.hpp @@ -0,0 +1,38 @@ +// +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_OPERATION_HPP +#define ASIO_DETAIL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_operation.hpp" +#else +# include "asio/detail/scheduler_operation.hpp" +#endif + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) +typedef win_iocp_operation operation; +#else +typedef scheduler_operation operation; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_OPERATION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/pipe_select_interrupter.hpp b/extern/asio-1.18.2/include/asio/detail/pipe_select_interrupter.hpp new file mode 100644 index 0000000..09b3f3b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/pipe_select_interrupter.hpp @@ -0,0 +1,89 @@ +// +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) +#if !defined(ASIO_WINDOWS_RUNTIME) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class pipe_select_interrupter +{ +public: + // Constructor. + ASIO_DECL pipe_select_interrupter(); + + // Destructor. + ASIO_DECL ~pipe_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupter. Returns true if the reset was successful. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/pipe_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/pop_options.hpp b/extern/asio-1.18.2/include/asio/detail/pop_options.hpp new file mode 100644 index 0000000..260e5e0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/pop_options.hpp @@ -0,0 +1,141 @@ +// +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +# pragma GCC diagnostic pop + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (pop) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# pragma GCC diagnostic pop + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) && !defined(__clang__) + +// Borland C++ + +# pragma option pop +# pragma nopushoptwarn +# pragma nopackwarning + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (pop) +# pragma pack (pop) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if defined(ASIO_CLR_WORKAROUND) +# undef generic +# undef ASIO_CLR_WORKAROUND +# endif +# endif + +#endif diff --git a/extern/asio-1.18.2/include/asio/detail/posix_event.hpp b/extern/asio-1.18.2/include/asio/detail/posix_event.hpp new file mode 100644 index 0000000..8a06b42 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_event.hpp @@ -0,0 +1,175 @@ +// +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_EVENT_HPP +#define ASIO_DETAIL_POSIX_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_event + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL posix_event(); + + // Destructor. + ~posix_event() + { + ::pthread_cond_destroy(&cond_); + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::pthread_cond_broadcast(&cond_); // Ignore EINVAL. + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + lock.unlock(); + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + timespec ts; +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \ + && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pthread_cond_timedwait_relative_np( + &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + ts.tv_sec += usec / 1000000; + ts.tv_nsec += (usec % 1000000) * 1000; + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec = ts.tv_nsec % 1000000000; + ::pthread_cond_timedwait(&cond_, + &lock.mutex().mutex_, &ts); // Ignore EINVAL. + } +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + ::pthread_cond_t cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_fd_set_adapter.hpp b/extern/asio-1.18.2/include/asio/detail/posix_fd_set_adapter.hpp new file mode 100644 index 0000000..230160b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_fd_set_adapter.hpp @@ -0,0 +1,118 @@ +// +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(__CYGWIN__) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class posix_fd_set_adapter : noncopyable +{ +public: + posix_fd_set_adapter() + : max_descriptor_(invalid_socket) + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + void reset() + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + bool set(socket_type descriptor) + { + if (descriptor < (socket_type)FD_SETSIZE) + { + if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_) + max_descriptor_ = descriptor; + FD_SET(descriptor, &fd_set_); + return true; + } + return false; + } + + void set(reactor_op_queue& operations, op_queue& ops) + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + if (!set(op_iter->first)) + { + asio::error_code ec(error::fd_set_failure); + operations.cancel_operations(op_iter, ops, ec); + } + } + } + + bool is_set(socket_type descriptor) const + { + return FD_ISSET(descriptor, &fd_set_) != 0; + } + + operator fd_set*() + { + return &fd_set_; + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue& operations, + op_queue& ops) const + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + if (is_set(op_iter->first)) + operations.perform_operations(op_iter, ops); + } + } + +private: + mutable fd_set fd_set_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(__CYGWIN__) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_global.hpp b/extern/asio-1.18.2/include/asio/detail/posix_global.hpp new file mode 100644 index 0000000..b7b113a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_global.hpp @@ -0,0 +1,80 @@ +// +// detail/posix_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_GLOBAL_HPP +#define ASIO_DETAIL_POSIX_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct posix_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.static_ptr_ = instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~posix_global_impl() + { + delete static_ptr_; + } + + static ::pthread_once_t init_once_; + static T* static_ptr_; + static posix_global_impl instance_; + T* ptr_; +}; + +template +::pthread_once_t posix_global_impl::init_once_ = PTHREAD_ONCE_INIT; + +template +T* posix_global_impl::static_ptr_ = 0; + +template +posix_global_impl posix_global_impl::instance_; + +template +T& posix_global() +{ + int result = ::pthread_once( + &posix_global_impl::init_once_, + &posix_global_impl::do_init); + + if (result != 0) + std::terminate(); + + return *posix_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_GLOBAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/posix_mutex.hpp new file mode 100644 index 0000000..ee0e8b2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_mutex.hpp @@ -0,0 +1,76 @@ +// +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_MUTEX_HPP +#define ASIO_DETAIL_POSIX_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_event; + +class posix_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock scoped_lock; + + // Constructor. + ASIO_DECL posix_mutex(); + + // Destructor. + ~posix_mutex() + { + ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + +private: + friend class posix_event; + ::pthread_mutex_t mutex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_signal_blocker.hpp b/extern/asio-1.18.2/include/asio/detail/posix_signal_blocker.hpp new file mode 100644 index 0000000..e0a4420 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_signal_blocker.hpp @@ -0,0 +1,85 @@ +// +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + posix_signal_blocker() + : blocked_(false) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + + // Destructor restores the previous signal mask. + ~posix_signal_blocker() + { + if (blocked_) + pthread_sigmask(SIG_SETMASK, &old_mask_, 0); + } + + // Block all signals for the calling thread. + void block() + { + if (!blocked_) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + } + + // Restore the previous signal mask. + void unblock() + { + if (blocked_) + blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0); + } + +private: + // Have signals been blocked. + bool blocked_; + + // The previous signal mask. + sigset_t old_mask_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_static_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/posix_static_mutex.hpp new file mode 100644 index 0000000..b9fdd48 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_static_mutex.hpp @@ -0,0 +1,64 @@ +// +// detail/posix_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP +#define ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct posix_static_mutex +{ + typedef asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + + ::pthread_mutex_t mutex_; +}; + +#define ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER } + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_thread.hpp b/extern/asio-1.18.2/include/asio/detail/posix_thread.hpp new file mode 100644 index 0000000..cd80af1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_thread.hpp @@ -0,0 +1,109 @@ +// +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_THREAD_HPP +#define ASIO_DETAIL_POSIX_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +extern "C" +{ + ASIO_DECL void* asio_detail_posix_thread_function(void* arg); +} + +class posix_thread + : private noncopyable +{ +public: + // Constructor. + template + posix_thread(Function f, unsigned int = 0) + : joined_(false) + { + start_thread(new func(f)); + } + + // Destructor. + ASIO_DECL ~posix_thread(); + + // Wait for the thread to exit. + ASIO_DECL void join(); + + // Get number of CPUs. + ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend void* asio_detail_posix_thread_function(void* arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ASIO_DECL void start_thread(func_base* arg); + + ::pthread_t thread_; + bool joined_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/posix_tss_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/posix_tss_ptr.hpp new file mode 100644 index 0000000..6d8b29f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/posix_tss_ptr.hpp @@ -0,0 +1,79 @@ +// +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_POSIX_TSS_PTR_HPP +#define ASIO_DETAIL_POSIX_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + +template +class posix_tss_ptr + : private noncopyable +{ +public: + // Constructor. + posix_tss_ptr() + { + posix_tss_ptr_create(tss_key_); + } + + // Destructor. + ~posix_tss_ptr() + { + ::pthread_key_delete(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast(::pthread_getspecific(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::pthread_setspecific(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + pthread_key_t tss_key_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/push_options.hpp b/extern/asio-1.18.2/include/asio/detail/push_options.hpp new file mode 100644 index 0000000..e05b756 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/push_options.hpp @@ -0,0 +1,191 @@ +// +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# if (__clang_major__ >= 6) +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif // (__clang_major__ >= 6) + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (push, 8) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) +# if (__GNUC__ >= 7) +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +# endif // (__GNUC__ >= 7) + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) && !defined(__clang__) + +// Borland C++ + +# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- +# pragma nopushoptwarn +# pragma nopackwarning +# if !defined(__MT__) +# error Multithreaded RTL must be selected. +# endif // !defined(__MT__) + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (disable:4103) +# pragma warning (push) +# pragma warning (disable:4127) +# pragma warning (disable:4180) +# pragma warning (disable:4244) +# pragma warning (disable:4355) +# pragma warning (disable:4510) +# pragma warning (disable:4512) +# pragma warning (disable:4610) +# pragma warning (disable:4675) +# if (_MSC_VER < 1600) +// Visual Studio 2008 generates spurious warnings about unused parameters. +# pragma warning (disable:4100) +# endif // (_MSC_VER < 1600) +# if defined(_M_IX86) && defined(_Wp64) +// The /Wp64 option is broken. If you want to check 64 bit portability, use a +// 64 bit compiler! +# pragma warning (disable:4311) +# pragma warning (disable:4312) +# endif // defined(_M_IX86) && defined(_Wp64) +# pragma pack (push, 8) +// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler +// has a tendency to incorrectly optimise away some calls to member template +// functions, even though those functions contain code that should not be +// optimised away! Therefore we will always disable this optimisation option +// for the MSVC6 compiler. +# if (_MSC_VER < 1300) +# pragma optimize ("g", off) +# endif +# if !defined(_MT) +# error Multithreaded RTL must be selected. +# endif // !defined(_MT) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if !defined(ASIO_DISABLE_CLR_WORKAROUND) +# if !defined(generic) +# define generic cpp_generic +# define ASIO_CLR_WORKAROUND +# endif +# endif +# endif + +#endif diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_descriptor_service.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_descriptor_service.hpp new file mode 100644 index 0000000..c640147 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_descriptor_service.hpp @@ -0,0 +1,416 @@ +// +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/buffer.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/descriptor_read_op.hpp" +#include "asio/detail/descriptor_write_op.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_wait_op.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/posix/descriptor_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_descriptor_service : + public execution_context_service_base +{ +public: + // The native type of a descriptor. + typedef int native_handle_type; + + // The implementation type of the descriptor. + class implementation_type + : private asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + state_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + // The current state of the descriptor. + descriptor_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + ASIO_DECL reactive_descriptor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new descriptor implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new descriptor implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl) ASIO_NOEXCEPT; + + // Move-assign from another descriptor implementation. + ASIO_DECL void move_assign(implementation_type& impl, + reactive_descriptor_service& other_service, + implementation_type& other_impl); + + // Destroy a descriptor implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native descriptor to a descriptor implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec); + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native descriptor representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.descriptor_; + } + + // Release ownership of the native descriptor representation. + ASIO_DECL native_handle_type release(implementation_type& impl); + + // Cancel all operations associated with the descriptor. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Perform an IO control command on the descriptor. + template + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the descriptor. + bool non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the descriptor. + asio::error_code non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_user_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native descriptor implementation. + bool native_non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native descriptor implementation. + asio::error_code native_non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Wait for the descriptor to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(implementation_type& impl, + posix::descriptor_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case posix::descriptor_base::wait_read: + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_write: + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_error: + descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the descriptor to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(implementation_type& impl, + posix::descriptor_base::wait_type w, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_wait")); + + int op_type; + switch (w) + { + case posix::descriptor_base::wait_read: + op_type = reactor::read_op; + break; + case posix::descriptor_base::wait_write: + op_type = reactor::write_op; + break; + case posix::descriptor_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Write some data to the descriptor. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + if (bufs_type::is_single_buffer) + { + return descriptor_ops::sync_write1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_write_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + buffer_sequence_adapter::all_empty(buffers)); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be written without blocking. + template + void async_write_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Read some data from the stream. Returns the number of bytes read. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + if (bufs_type::is_single_buffer) + { + return descriptor_ops::sync_read1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_read_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some")); + + start_op(impl, reactor::read_op, p.p, is_continuation, true, + buffer_sequence_adapter::all_empty(buffers)); + p.v = p.p = 0; + } + + // Wait until data can be read without blocking. + template + void async_read_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some(null_buffers)")); + + start_op(impl, reactor::read_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +private: + // Start the asynchronous operation. + ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_descriptor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_null_buffers_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 0000000..48214dc --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,98 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(const asio::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_serial_port_service.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_serial_port_service.hpp new file mode 100644 index 0000000..e5a605c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_serial_port_service.hpp @@ -0,0 +1,237 @@ +// +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend reactive_descriptor_service to provide serial port support. +class reactive_serial_port_service : + public execution_context_service_base +{ +public: + // The native type of a serial port. + typedef reactive_descriptor_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef reactive_descriptor_service::implementation_type implementation_type; + + ASIO_DECL reactive_serial_port_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + descriptor_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + descriptor_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + reactive_serial_port_service& other_service, + implementation_type& other_impl) + { + descriptor_service_.move_assign(impl, + other_service.descriptor_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + descriptor_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); + + // Assign a native descriptor to a serial port implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec) + { + return descriptor_service_.assign(impl, native_descriptor, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return descriptor_service_.is_open(impl); + } + + // Destroy a serial port implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return descriptor_service_.native_handle(impl); + } + + // Cancel all operations associated with the serial port. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template + asio::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, asio::error_code& ec) + { + return do_set_option(impl, + &reactive_serial_port_service::store_option, + &option, ec); + } + + // Get an option from the serial port. + template + asio::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, asio::error_code& ec) const + { + return do_get_option(impl, + &reactive_serial_port_service::load_option, + &option, ec); + } + + // Send a break sequence to the serial port. + asio::error_code send_break(implementation_type& impl, + asio::error_code& ec) + { + int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0); + descriptor_ops::get_last_error(ec, result < 0); + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_write_some(impl, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_read_some(impl, buffers, handler, io_ex); + } + +private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, termios&, asio::error_code&); + + // Helper function template to store a serial port option. + template + static asio::error_code store_option(const void* option, + termios& storage, asio::error_code& ec) + { + static_cast(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const termios&, asio::error_code&); + + // Helper function template to load a serial port option. + template + static asio::error_code load_option(void* option, + const termios& storage, asio::error_code& ec) + { + static_cast(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + reactive_descriptor_service descriptor_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_accept_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 0000000..ac03671 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,242 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast(base)); + + socket_type new_socket = invalid_socket; + status result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket) + ? done : not_done; + o->new_socket_.reset(new_socket); + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_)); + + return result; + } + + void do_assign() + { + if (new_socket_.get() != invalid_socket) + { + if (peer_endpoint_) + peer_endpoint_->resize(addrlen_); + peer_.assign(protocol_, new_socket_.get(), ec_); + if (!ec_) + new_socket_.release(); + } + } + +private: + socket_type socket_; + socket_ops::state_type state_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + std::size_t addrlen_; +}; + +template +class reactive_socket_accept_op : + public reactive_socket_accept_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_accept_op_base( + success_ec, socket, state, peer, protocol, peer_endpoint, + &reactive_socket_accept_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +#if defined(ASIO_HAS_MOVE) + +template +class reactive_socket_move_accept_op : + private Protocol::socket::template rebind_executor::other, + public reactive_socket_accept_op_base< + typename Protocol::socket::template rebind_executor::other, + Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); + + reactive_socket_move_accept_op(const asio::error_code& success_ec, + const PeerIoExecutor& peer_io_ex, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + : peer_socket_type(peer_io_ex), + reactive_socket_accept_op_base( + success_ec, socket, state, *this, protocol, peer_endpoint, + &reactive_socket_move_accept_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_move_accept_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2 + handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + ASIO_MOVE_CAST(peer_socket_type)(*o)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + typedef typename Protocol::socket::template + rebind_executor::other peer_socket_type; + + Handler handler_; + handler_work work_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_connect_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 0000000..956bc52 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,123 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(const asio::error_code& success_ec, + socket_type socket, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast(base)); + + status result = socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_)); + + return result; + } + +private: + socket_type socket_; +}; + +template +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(const asio::error_code& success_ec, + socket_type socket, Handler& handler, const IoExecutor& io_ex) + : reactive_socket_connect_op_base(success_ec, socket, + &reactive_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_recv_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 0000000..d30f4ab --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,159 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recv1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ == 0) + result = done_and_exhausted; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recv_op : + public reactive_socket_recv_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_recv_op_base(success_ec, socket, + state, buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvfrom_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 0000000..0d7673a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,164 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(const asio::error_code& success_ec, + socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + std::size_t addr_len = o->sender_endpoint_.capacity(); + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recvfrom1( + o->socket_, bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(const asio::error_code& success_ec, + socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_recvfrom_op_base( + success_ec, socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvmsg_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvmsg_op.hpp new file mode 100644 index 0000000..b387f04 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_recvmsg_op.hpp @@ -0,0 +1,145 @@ +// +// detail/reactive_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_recvmsg_op_base : public reactor_op +{ +public: + reactive_socket_recvmsg_op_base(const asio::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_recvmsg_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + in_flags_(in_flags), + out_flags_(out_flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvmsg_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = socket_ops::non_blocking_recvmsg(o->socket_, + bufs.buffers(), bufs.count(), + o->in_flags_, o->out_flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + MutableBufferSequence buffers_; + socket_base::message_flags in_flags_; + socket_base::message_flags& out_flags_; +}; + +template +class reactive_socket_recvmsg_op : + public reactive_socket_recvmsg_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); + + reactive_socket_recvmsg_op(const asio::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_recvmsg_op_base( + success_ec, socket, buffers, in_flags, out_flags, + &reactive_socket_recvmsg_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvmsg_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_send_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 0000000..5a77856 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,162 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_send_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_send1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs_type::first(o->buffers_).size()) + result = done_and_exhausted; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + } + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_send_op : + public reactive_socket_send_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_send_op_base(success_ec, socket, + state, buffers, flags, &reactive_socket_send_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_sendto_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 0000000..28bff66 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,156 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(const asio::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast(base)); + + typedef buffer_sequence_adapter bufs_type; + + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_sendto1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(const asio::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_sendto_op_base( + success_ec, socket, buffers, endpoint, flags, + &reactive_socket_sendto_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_service.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_service.hpp new file mode 100644 index 0000000..64c7722 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_service.hpp @@ -0,0 +1,528 @@ +// +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_accept_op.hpp" +#include "asio/detail/reactive_socket_connect_op.hpp" +#include "asio/detail/reactive_socket_recvfrom_op.hpp" +#include "asio/detail/reactive_socket_sendto_op.hpp" +#include "asio/detail/reactive_socket_service_base.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_socket_service : + public execution_context_service_base >, + public reactive_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct implementation_type : + reactive_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + reactive_socket_service(execution_context& context) + : execution_context_service_base< + reactive_socket_service >(context), + reactive_socket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) ASIO_NOEXCEPT + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + reactive_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type& impl, + reactive_socket_service&, + typename reactive_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + return impl.socket_; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_sendto1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + destination.data(), destination.size(), ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_sendto_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, destination, flags, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd; + if (bufs_type::is_single_buffer) + { + bytes_recvd = socket_ops::sync_recvfrom1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + sender_endpoint.data(), &addr_len, ec); + } + else + { + bufs_type bufs(buffers); + bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + } + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvfrom_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + int protocol = impl.protocol_.type(); + p.p = new (p.v) op(success_ec_, impl.socket_, protocol, + buffers, sender_endpoint, flags, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Accept a new connection. + template + asio::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects must be + // valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_accept_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + peer, impl.protocol_, peer_endpoint, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, peer.is_open()); + p.v = p.p = 0; + } + +#if defined(ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer_endpoint object must be valid until + // the accept's handler is invoked. + template + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_move_accept_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, + impl.state_, impl.protocol_, peer_endpoint, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } +#endif // defined(ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_connect_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, p.p, is_continuation, + peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_socket_service_base.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 0000000..e544188 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,541 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_recv_op.hpp" +#include "asio/detail/reactive_socket_recvmsg_op.hpp" +#include "asio/detail/reactive_socket_send_op.hpp" +#include "asio/detail/reactive_wait_op.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + ASIO_DECL reactive_socket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl) ASIO_NOEXCEPT; + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + reactive_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + int op_type; + switch (w) + { + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Send the given data to the peer. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_send1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + typedef buffer_sequence_adapter bufs_type; + + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_recv1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, in_flags, out_flags, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (in_flags & socket_base::message_out_of_band) == 0, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, handler, io_ex); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + const native_handle_type& native_socket, asio::error_code& ec); + + // Start the asynchronous read or write operation. + ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // Start the asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open); + + // Start the asynchronous connect operation. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_IOCP) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactive_wait_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactive_wait_op.hpp new file mode 100644 index 0000000..c7e2eb8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactive_wait_op.hpp @@ -0,0 +1,98 @@ +// +// detail/reactive_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTIVE_WAIT_OP_HPP +#define ASIO_DETAIL_REACTIVE_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactive_wait_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); + + reactive_wait_op(const asio::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_wait_op::do_perform, + &reactive_wait_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_wait_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_WAIT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactor.hpp b/extern/asio-1.18.2/include/asio/detail/reactor.hpp new file mode 100644 index 0000000..03a601c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactor.hpp @@ -0,0 +1,32 @@ +// +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTOR_HPP +#define ASIO_DETAIL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/reactor_fwd.hpp" + +#if defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor.hpp" +#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_reactor.hpp" +#else +# include "asio/detail/select_reactor.hpp" +#endif + +#endif // ASIO_DETAIL_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactor_fwd.hpp b/extern/asio-1.18.2/include/asio/detail/reactor_fwd.hpp new file mode 100644 index 0000000..b9c0846 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactor_fwd.hpp @@ -0,0 +1,40 @@ +// +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTOR_FWD_HPP +#define ASIO_DETAIL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +typedef class null_reactor reactor; +#elif defined(ASIO_HAS_IOCP) +typedef class select_reactor reactor; +#elif defined(ASIO_HAS_EPOLL) +typedef class epoll_reactor reactor; +#elif defined(ASIO_HAS_KQUEUE) +typedef class kqueue_reactor reactor; +#elif defined(ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor reactor; +#else +typedef class select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactor_op.hpp b/extern/asio-1.18.2/include/asio/detail/reactor_op.hpp new file mode 100644 index 0000000..6eda89e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactor_op.hpp @@ -0,0 +1,67 @@ +// +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTOR_OP_HPP +#define ASIO_DETAIL_REACTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactor_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // Status returned by perform function. May be used to decide whether it is + // worth performing more operations on the descriptor immediately. + enum status { not_done, done, done_and_exhausted }; + + // Perform the operation. Returns true if it is finished. + status perform() + { + return perform_func_(this); + } + +protected: + typedef status (*perform_func_type)(reactor_op*); + + reactor_op(const asio::error_code& success_ec, + perform_func_type perform_func, func_type complete_func) + : operation(complete_func), + ec_(success_ec), + bytes_transferred_(0), + perform_func_(perform_func) + { + } + +private: + perform_func_type perform_func_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTOR_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/reactor_op_queue.hpp b/extern/asio-1.18.2/include/asio/detail/reactor_op_queue.hpp new file mode 100644 index 0000000..c31752b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/reactor_op_queue.hpp @@ -0,0 +1,168 @@ +// +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REACTOR_OP_QUEUE_HPP +#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/hash_map.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class reactor_op_queue + : private noncopyable +{ +public: + typedef Descriptor key_type; + + struct mapped_type : op_queue + { + mapped_type() {} + mapped_type(const mapped_type&) {} + void operator=(const mapped_type&) {} + }; + + typedef typename hash_map::value_type value_type; + typedef typename hash_map::iterator iterator; + + // Constructor. + reactor_op_queue() + : operations_() + { + } + + // Obtain iterators to all registered descriptors. + iterator begin() { return operations_.begin(); } + iterator end() { return operations_.end(); } + + // Add a new operation to the queue. Returns true if this is the only + // operation for the given descriptor, in which case the reactor's event + // demultiplexing function call may need to be interrupted and restarted. + bool enqueue_operation(Descriptor descriptor, reactor_op* op) + { + std::pair entry = + operations_.insert(value_type(descriptor, mapped_type())); + entry.first->second.push(op); + return entry.second; + } + + // Cancel all operations associated with the descriptor identified by the + // supplied iterator. Any operations pending for the descriptor will be + // cancelled. Returns true if any operations were cancelled, in which case + // the reactor's event demultiplexing function may need to be interrupted and + // restarted. + bool cancel_operations(iterator i, op_queue& ops, + const asio::error_code& ec = + asio::error::operation_aborted) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + op->ec_ = ec; + i->second.pop(); + ops.push(op); + } + operations_.erase(i); + return true; + } + + return false; + } + + // Cancel all operations associated with the descriptor. Any operations + // pending for the descriptor will be cancelled. Returns true if any + // operations were cancelled, in which case the reactor's event + // demultiplexing function may need to be interrupted and restarted. + bool cancel_operations(Descriptor descriptor, op_queue& ops, + const asio::error_code& ec = + asio::error::operation_aborted) + { + return this->cancel_operations(operations_.find(descriptor), ops, ec); + } + + // Whether there are no operations in the queue. + bool empty() const + { + return operations_.empty(); + } + + // Determine whether there are any operations associated with the descriptor. + bool has_operation(Descriptor descriptor) const + { + return operations_.find(descriptor) != operations_.end(); + } + + // Perform the operations corresponding to the descriptor identified by the + // supplied iterator. Returns true if there are still unfinished operations + // queued for the descriptor. + bool perform_operations(iterator i, op_queue& ops) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + if (op->perform()) + { + i->second.pop(); + ops.push(op); + } + else + { + return true; + } + } + operations_.erase(i); + } + return false; + } + + // Perform the operations corresponding to the descriptor. Returns true if + // there are still unfinished operations queued for the descriptor. + bool perform_operations(Descriptor descriptor, op_queue& ops) + { + return this->perform_operations(operations_.find(descriptor), ops); + } + + // Get all operations owned by the queue. + void get_all_operations(op_queue& ops) + { + iterator i = operations_.begin(); + while (i != operations_.end()) + { + iterator op_iter = i++; + ops.push(op_iter->second); + operations_.erase(op_iter); + } + } + +private: + // The operations that are currently executing asynchronously. + hash_map operations_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/recycling_allocator.hpp b/extern/asio-1.18.2/include/asio/detail/recycling_allocator.hpp new file mode 100644 index 0000000..23e59b1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/recycling_allocator.hpp @@ -0,0 +1,104 @@ +// +// detail/recycling_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP +#define ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class recycling_allocator +{ +public: + typedef T value_type; + + template + struct rebind + { + typedef recycling_allocator other; + }; + + recycling_allocator() + { + } + + template + recycling_allocator(const recycling_allocator&) + { + } + + T* allocate(std::size_t n) + { + void* p = thread_info_base::allocate(Purpose(), + thread_context::top_of_thread_call_stack(), sizeof(T) * n); + return static_cast(p); + } + + void deallocate(T* p, std::size_t n) + { + thread_info_base::deallocate(Purpose(), + thread_context::top_of_thread_call_stack(), p, sizeof(T) * n); + } +}; + +template +class recycling_allocator +{ +public: + typedef void value_type; + + template + struct rebind + { + typedef recycling_allocator other; + }; + + recycling_allocator() + { + } + + template + recycling_allocator(const recycling_allocator&) + { + } +}; + +template +struct get_recycling_allocator +{ + typedef Allocator type; + static type get(const Allocator& a) { return a; } +}; + +template +struct get_recycling_allocator, Purpose> +{ + typedef recycling_allocator type; + static type get(const std::allocator&) { return type(); } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/regex_fwd.hpp b/extern/asio-1.18.2/include/asio/detail/regex_fwd.hpp new file mode 100644 index 0000000..bde7402 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/regex_fwd.hpp @@ -0,0 +1,44 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_REGEX_FWD_HPP +#define ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_BOOST_REGEX) + +#include +#include +#if BOOST_VERSION >= 107600 +# if defined(BOOST_REGEX_CXX03) +# include +# else // defined(BOOST_REGEX_CXX03) +# include +# endif // defined(BOOST_REGEX_CXX03) +#else // BOOST_VERSION >= 107600 +# include +#endif // BOOST_VERSION >= 107600 + +namespace boost { + +template +struct sub_match; + +template +class match_results; + +} // namespace boost + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +#endif // ASIO_DETAIL_REGEX_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/resolve_endpoint_op.hpp b/extern/asio-1.18.2/include/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 0000000..bf494f5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,140 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP +#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/ip/basic_resolver_results.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class resolve_endpoint_op : public resolve_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef asio::ip::basic_resolver_results results_type; + +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, + const endpoint_type& endpoint, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) + : resolve_op(&resolve_endpoint_op::do_complete), + cancel_token_(cancel_token), + endpoint_(endpoint), + scheduler_(sched), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner && owner != &o->scheduler_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), + o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, + o->endpoint_.protocol().type(), o->ec_); + o->results_ = results_type::create(o->endpoint_, host_name, service_name); + + // Pass operation back to main io_context for completion. + o->scheduler_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->results_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + scheduler_impl& scheduler_; + Handler handler_; + handler_work work_; + results_type results_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/resolve_op.hpp b/extern/asio-1.18.2/include/asio/detail/resolve_op.hpp new file mode 100644 index 0000000..e0ac00b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/resolve_op.hpp @@ -0,0 +1,45 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RESOLVE_OP_HPP +#define ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolve_op : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + resolve_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/resolve_query_op.hpp b/extern/asio-1.18.2/include/asio/detail/resolve_query_op.hpp new file mode 100644 index 0000000..5a2ffa7 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/resolve_query_op.hpp @@ -0,0 +1,150 @@ +// +// detail/resolve_query_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RESOLVE_QUERY_OP_HPP +#define ASIO_DETAIL_RESOLVE_QUERY_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class resolve_query_op : public resolve_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_query_op); + + typedef asio::ip::basic_resolver_query query_type; + typedef asio::ip::basic_resolver_results results_type; + +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + + resolve_query_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& qry, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) + : resolve_op(&resolve_query_op::do_complete), + cancel_token_(cancel_token), + query_(qry), + scheduler_(sched), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex), + addrinfo_(0) + { + } + + ~resolve_query_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_query_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner && owner != &o->scheduler_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_context for completion. + o->scheduler_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, results_type()); + p.h = asio::detail::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = results_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + scheduler_impl& scheduler_; + Handler handler_; + handler_work work_; + asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVE_QUERY_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/resolver_service.hpp b/extern/asio-1.18.2/include/asio/detail/resolver_service.hpp new file mode 100644 index 0000000..006b35c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/resolver_service.hpp @@ -0,0 +1,145 @@ +// +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RESOLVER_SERVICE_HPP +#define ASIO_DETAIL_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_endpoint_op.hpp" +#include "asio/detail/resolve_query_op.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class resolver_service : + public execution_context_service_base >, + public resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef asio::ip::basic_resolver_query query_type; + + // The results type. + typedef asio::ip::basic_resolver_results results_type; + + // Constructor. + resolver_service(execution_context& context) + : execution_context_service_base >(context), + resolver_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Perform any fork-related housekeeping. + void notify_fork(execution_context::fork_event fork_ev) + { + this->base_notify_fork(fork_ev); + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, const query_type& qry, + asio::error_code& ec) + { + asio::detail::addrinfo_type* address_info = 0; + + socket_ops::getaddrinfo(qry.host_name().c_str(), + qry.service_name().c_str(), qry.hints(), &address_info, ec); + auto_addrinfo auto_address_info(address_info); + + return ec ? results_type() : results_type::create( + address_info, qry.host_name(), qry.service_name()); + } + + // Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& qry, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef resolve_query_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, qry, scheduler_, handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type& endpoint, asio::error_code& ec) + { + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); + + return ec ? results_type() : results_type::create( + endpoint, host_name, service_name); + } + + // Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef resolve_endpoint_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/resolver_service_base.hpp b/extern/asio-1.18.2/include/asio/detail/resolver_service_base.hpp new file mode 100644 index 0000000..0df30f4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/resolver_service_base.hpp @@ -0,0 +1,158 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP +#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/thread.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + ASIO_DECL resolver_service_base(execution_context& context); + + // Destructor. + ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Perform any fork-related housekeeping. + ASIO_DECL void base_notify_fork( + execution_context::fork_event fork_ev); + + // Construct a new resolver implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + ASIO_DECL void destroy(implementation_type&); + + // Move-construct a new resolver implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another resolver implementation. + ASIO_DECL void move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl); + + // Move-construct a new timer implementation. + void converting_move_construct(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) + { + move_construct(impl, other_impl); + } + + // Move-assign from another timer implementation. + void converting_move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl) + { + move_assign(impl, other_service, other_impl); + } + + // Cancel pending asynchronous operations. + ASIO_DECL void cancel(implementation_type& impl); + +protected: + // Helper function to start an asynchronous resolve operation. + ASIO_DECL void start_resolve_op(resolve_op* op); + +#if !defined(ASIO_WINDOWS_RUNTIME) + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private asio::detail::noncopyable + { + public: + explicit auto_addrinfo(asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + asio::detail::addrinfo_type* ai_; + }; +#endif // !defined(ASIO_WINDOWS_RUNTIME) + + // Helper class to run the work scheduler in a thread. + class work_scheduler_runner; + + // Start the work scheduler if it's not already running. + ASIO_DECL void start_work_thread(); + + // The scheduler implementation used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + +private: + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // Private scheduler used for performing asynchronous host resolution. + asio::detail::scoped_ptr work_scheduler_; + + // Thread used for running the work io_context's run loop. + asio::detail::scoped_ptr work_thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/resolver_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/scheduler.hpp b/extern/asio-1.18.2/include/asio/detail/scheduler.hpp new file mode 100644 index 0000000..ce8a7e1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/scheduler.hpp @@ -0,0 +1,229 @@ +// +// detail/scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SCHEDULER_HPP +#define ASIO_DETAIL_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/error_code.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/conditionally_enabled_event.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_fwd.hpp" +#include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/thread_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct scheduler_thread_info; + +class scheduler + : public execution_context_service_base, + public thread_context +{ +public: + typedef scheduler_operation operation; + + // Constructor. Specifies the number of concurrent threads that are likely to + // run the scheduler. If set to 1 certain optimisation are performed. + ASIO_DECL scheduler(asio::execution_context& ctx, + int concurrency_hint = 0, bool own_thread = true); + + // Destructor. + ASIO_DECL ~scheduler(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Initialise the task, if required. + ASIO_DECL void init_task(); + + // Run the event loop until interrupted or no more work. + ASIO_DECL std::size_t run(asio::error_code& ec); + + // Run until interrupted or one operation is performed. + ASIO_DECL std::size_t run_one(asio::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + ASIO_DECL std::size_t wait_one( + long usec, asio::error_code& ec); + + // Poll for operations without blocking. + ASIO_DECL std::size_t poll(asio::error_code& ec); + + // Poll for one operation without blocking. + ASIO_DECL std::size_t poll_one(asio::error_code& ec); + + // Interrupt the event processing loop. + ASIO_DECL void stop(); + + // Determine whether the scheduler is stopped. + ASIO_DECL bool stopped() const; + + // Restart in preparation for a subsequent run invocation. + ASIO_DECL void restart(); + + // Notify that some work has started. + void work_started() + { + ++outstanding_work_; + } + + // Used to compensate for a forthcoming work_finished call. Must be called + // from within a scheduler-owned thread. + ASIO_DECL void compensating_work_started(); + + // Notify that some work has finished. + void work_finished() + { + if (--outstanding_work_ == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + ASIO_DECL bool can_dispatch(); + + /// Capture the current exception so it can be rethrown from a run function. + ASIO_DECL void capture_current_exception(); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + ASIO_DECL void post_immediate_completion( + operation* op, bool is_continuation); + + // Request invocation of the given operations and return immediately. Assumes + // that work_started() has not yet been called for the operations. + ASIO_DECL void post_immediate_completions(std::size_t n, + op_queue& ops, bool is_continuation); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + ASIO_DECL void post_deferred_completion(operation* op); + + // Request invocation of the given operations and return immediately. Assumes + // that work_started() was previously called for each operation. + ASIO_DECL void post_deferred_completions(op_queue& ops); + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + ASIO_DECL void do_dispatch(operation* op); + + // Process unfinished operations as part of a shutdownoperation. Assumes that + // work_started() was previously called for the operations. + ASIO_DECL void abandon_operations(op_queue& ops); + + // Get the concurrency hint that was used to initialise the scheduler. + int concurrency_hint() const + { + return concurrency_hint_; + } + +private: + // The mutex type used by this scheduler. + typedef conditionally_enabled_mutex mutex; + + // The event type used by this scheduler. + typedef conditionally_enabled_event event; + + // Structure containing thread-specific data. + typedef scheduler_thread_info thread_info; + + // Run at most one operation. May block. + ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock, + thread_info& this_thread, const asio::error_code& ec); + + // Run at most one operation with a timeout. May block. + ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock, + thread_info& this_thread, long usec, const asio::error_code& ec); + + // Poll for at most one operation. + ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock, + thread_info& this_thread, const asio::error_code& ec); + + // Stop the task and all idle threads. + ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); + + // Wake a single idle thread, or the task, and always unlock the mutex. + ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); + + // Helper class to run the scheduler in its own thread. + class thread_function; + friend class thread_function; + + // Helper class to perform task-related operations on block exit. + struct task_cleanup; + friend struct task_cleanup; + + // Helper class to call work-related operations on block exit. + struct work_cleanup; + friend struct work_cleanup; + + // Whether to optimise for single-threaded use cases. + const bool one_thread_; + + // Mutex to protect access to internal data. + mutable mutex mutex_; + + // Event to wake up blocked threads. + event wakeup_event_; + + // The task to be run by this service. + reactor* task_; + + // Operation object to represent the position of the task in the queue. + struct task_operation : operation + { + task_operation() : operation(0) {} + } task_operation_; + + // Whether the task has been interrupted. + bool task_interrupted_; + + // The count of unfinished work. + atomic_count outstanding_work_; + + // The queue of handlers that are ready to be delivered. + op_queue op_queue_; + + // Flag to indicate that the dispatcher has been stopped. + bool stopped_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; + + // The concurrency hint used to initialise the scheduler. + const int concurrency_hint_; + + // The thread that is running the scheduler. + asio::detail::thread* thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/scheduler.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SCHEDULER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/scheduler_operation.hpp b/extern/asio-1.18.2/include/asio/detail/scheduler_operation.hpp new file mode 100644 index 0000000..1ca4964 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/scheduler_operation.hpp @@ -0,0 +1,78 @@ +// +// detail/scheduler_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SCHEDULER_OPERATION_HPP +#define ASIO_DETAIL_SCHEDULER_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/error_code.hpp" +#include "asio/detail/handler_tracking.hpp" +#include "asio/detail/op_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class scheduler_operation ASIO_INHERIT_TRACKED_HANDLER +{ +public: + typedef scheduler_operation operation_type; + + void complete(void* owner, const asio::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, asio::error_code(), 0); + } + +protected: + typedef void (*func_type)(void*, + scheduler_operation*, + const asio::error_code&, std::size_t); + + scheduler_operation(func_type func) + : next_(0), + func_(func), + task_result_(0) + { + } + + // Prevents deletion through this type. + ~scheduler_operation() + { + } + +private: + friend class op_queue_access; + scheduler_operation* next_; + func_type func_; +protected: + friend class scheduler; + unsigned int task_result_; // Passed into bytes transferred. +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCHEDULER_OPERATION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/scheduler_thread_info.hpp b/extern/asio-1.18.2/include/asio/detail/scheduler_thread_info.hpp new file mode 100644 index 0000000..3202e3c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/scheduler_thread_info.hpp @@ -0,0 +1,40 @@ +// +// detail/scheduler_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP +#define ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/op_queue.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; +class scheduler_operation; + +struct scheduler_thread_info : public thread_info_base +{ + op_queue private_op_queue; + long private_outstanding_work; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/scoped_lock.hpp b/extern/asio-1.18.2/include/asio/detail/scoped_lock.hpp new file mode 100644 index 0000000..273d702 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/scoped_lock.hpp @@ -0,0 +1,101 @@ +// +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SCOPED_LOCK_HPP +#define ASIO_DETAIL_SCOPED_LOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to lock and unlock a mutex automatically. +template +class scoped_lock + : private noncopyable +{ +public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(Mutex& m, adopt_lock_t) + : mutex_(m), + locked_(true) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(Mutex& m) + : mutex_(m) + { + mutex_.lock(); + locked_ = true; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (!locked_) + { + mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + +private: + // The underlying mutex. + Mutex& mutex_; + + // Whether the mutex is currently locked or unlocked. + bool locked_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCOPED_LOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/scoped_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/scoped_ptr.hpp new file mode 100644 index 0000000..2eab4c9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/scoped_ptr.hpp @@ -0,0 +1,87 @@ +// +// detail/scoped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SCOPED_PTR_HPP +#define ASIO_DETAIL_SCOPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class scoped_ptr +{ +public: + // Constructor. + explicit scoped_ptr(T* p = 0) + : p_(p) + { + } + + // Destructor. + ~scoped_ptr() + { + delete p_; + } + + // Access. + T* get() + { + return p_; + } + + // Access. + T* operator->() + { + return p_; + } + + // Dereference. + T& operator*() + { + return *p_; + } + + // Reset pointer. + void reset(T* p = 0) + { + delete p_; + p_ = p; + } + + // Release ownership of the pointer. + T* release() + { + T* tmp = p_; + p_ = 0; + return tmp; + } + +private: + // Disallow copying and assignment. + scoped_ptr(const scoped_ptr&); + scoped_ptr& operator=(const scoped_ptr&); + + T* p_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCOPED_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/select_interrupter.hpp b/extern/asio-1.18.2/include/asio/detail/select_interrupter.hpp new file mode 100644 index 0000000..a542373 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/select_interrupter.hpp @@ -0,0 +1,46 @@ +// +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include "asio/detail/socket_select_interrupter.hpp" +#elif defined(ASIO_HAS_EVENTFD) +# include "asio/detail/eventfd_select_interrupter.hpp" +#else +# include "asio/detail/pipe_select_interrupter.hpp" +#endif + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef socket_select_interrupter select_interrupter; +#elif defined(ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; +#else +typedef pipe_select_interrupter select_interrupter; +#endif + +} // namespace detail +} // namespace asio + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/select_reactor.hpp b/extern/asio-1.18.2/include/asio/detail/select_reactor.hpp new file mode 100644 index 0000000..50cb574 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/select_reactor.hpp @@ -0,0 +1,238 @@ +// +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SELECT_REACTOR_HPP +#define ASIO_DETAIL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include +#include "asio/detail/fd_set_adapter.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/thread.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class select_reactor + : public execution_context_service_base +{ +public: +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 3, max_ops = 4 }; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 1, max_ops = 3 }; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + ASIO_DECL select_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~select_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task, but only if the reactor is not in its own thread. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool is_continuation, bool); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run select once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: +#if defined(ASIO_HAS_IOCP) + // Run the select loop in the thread. + ASIO_DECL void run_thread(); +#endif // defined(ASIO_HAS_IOCP) + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the select call. + ASIO_DECL timeval* get_timeout(long usec, timeval& tv); + + // Cancel all operations associated with the given descriptor. This function + // does not acquire the select_reactor's mutex. + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); + + // The scheduler implementation used to post completions. +# if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_type; +# else // defined(ASIO_HAS_IOCP) + typedef class scheduler scheduler_type; +# endif // defined(ASIO_HAS_IOCP) + scheduler_type& scheduler_; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // The interrupter is used to break a blocking select call. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; + + // The file descriptor sets to be passed to the select system call. + fd_set_adapter fd_sets_[max_select_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + +#if defined(ASIO_HAS_IOCP) + // Helper class to run the reactor loop in a thread. + class thread_function; + friend class thread_function; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + asio::detail::thread* thread_; +#endif // defined(ASIO_HAS_IOCP) + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/select_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/select_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/service_registry.hpp b/extern/asio-1.18.2/include/asio/detail/service_registry.hpp new file mode 100644 index 0000000..2c7f4a5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/service_registry.hpp @@ -0,0 +1,164 @@ +// +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SERVICE_REGISTRY_HPP +#define ASIO_DETAIL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class io_context; + +namespace detail { + +template +class typeid_wrapper {}; + +class service_registry + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL service_registry(execution_context& owner); + + // Destructor. + ASIO_DECL ~service_registry(); + + // Shutdown all services. + ASIO_DECL void shutdown_services(); + + // Destroy all services. + ASIO_DECL void destroy_services(); + + // Notify all services of a fork event. + ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + template + Service& use_service(); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + // This overload is used for backwards compatibility with services that + // inherit from io_context::service. + template + Service& use_service(io_context& owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + template + void add_service(Service* new_service); + + // Check whether a service object of the specified type already exists. + template + bool has_service() const; + +private: + // Initalise a service's key when the key_type typedef is not available. + template + static void init_key(execution_context::service::key& key, ...); + +#if !defined(ASIO_NO_TYPEID) + // Initalise a service's key when the key_type typedef is available. + template + static void init_key(execution_context::service::key& key, + typename enable_if< + is_base_of::value>::type*); +#endif // !defined(ASIO_NO_TYPEID) + + // Initialise a service's key based on its id. + ASIO_DECL static void init_key_from_id( + execution_context::service::key& key, + const execution_context::id& id); + +#if !defined(ASIO_NO_TYPEID) + // Initialise a service's key based on its id. + template + static void init_key_from_id(execution_context::service::key& key, + const service_id& /*id*/); +#endif // !defined(ASIO_NO_TYPEID) + + // Check if a service matches the given id. + ASIO_DECL static bool keys_match( + const execution_context::service::key& key1, + const execution_context::service::key& key2); + + // The type of a factory function used for creating a service instance. + typedef execution_context::service*(*factory_type)(void*); + + // Factory function for creating a service instance. + template + static execution_context::service* create(void* owner); + + // Destroy a service instance. + ASIO_DECL static void destroy(execution_context::service* service); + + // Helper class to manage service pointers. + struct auto_service_ptr; + friend struct auto_service_ptr; + struct auto_service_ptr + { + execution_context::service* ptr_; + ~auto_service_ptr() { destroy(ptr_); } + }; + + // Get the service object corresponding to the specified service key. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + ASIO_DECL execution_context::service* do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + ASIO_DECL void do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service); + + // Check whether a service object with the specified key already exists. + ASIO_DECL bool do_has_service( + const execution_context::service::key& key) const; + + // Mutex to protect access to internal data. + mutable asio::detail::mutex mutex_; + + // The owner of this service registry and the services it contains. + execution_context& owner_; + + // The first service in the list of contained services. + execution_context::service* first_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/service_registry.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/service_registry.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/signal_blocker.hpp b/extern/asio-1.18.2/include/asio/detail/signal_blocker.hpp new file mode 100644 index 0000000..bbe7b3f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/signal_blocker.hpp @@ -0,0 +1,44 @@ +// +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include "asio/detail/null_signal_blocker.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_signal_blocker.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef null_signal_blocker signal_blocker; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_signal_blocker signal_blocker; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/signal_handler.hpp b/extern/asio-1.18.2/include/asio/detail/signal_handler.hpp new file mode 100644 index 0000000..0153133 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/signal_handler.hpp @@ -0,0 +1,90 @@ +// +// detail/signal_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SIGNAL_HANDLER_HPP +#define ASIO_DETAIL_SIGNAL_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/signal_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class signal_handler : public signal_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(signal_handler); + + signal_handler(Handler& h, const IoExecutor& io_ex) + : signal_op(&signal_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + signal_handler* h(static_cast(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + + ASIO_HANDLER_COMPLETION((*h)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + h->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(h->handler_, h->ec_, h->signal_number_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SIGNAL_HANDLER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/signal_init.hpp b/extern/asio-1.18.2/include/asio/detail/signal_init.hpp new file mode 100644 index 0000000..80c7a7a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/signal_init.hpp @@ -0,0 +1,47 @@ +// +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SIGNAL_INIT_HPP +#define ASIO_DETAIL_SIGNAL_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class signal_init +{ +public: + // Constructor. + signal_init() + { + std::signal(Signal, SIG_IGN); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/signal_op.hpp b/extern/asio-1.18.2/include/asio/detail/signal_op.hpp new file mode 100644 index 0000000..297c0d9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/signal_op.hpp @@ -0,0 +1,49 @@ +// +// detail/signal_op.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SIGNAL_OP_HPP +#define ASIO_DETAIL_SIGNAL_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class signal_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The signal number to be passed to the completion handler. + int signal_number_; + +protected: + signal_op(func_type func) + : operation(func), + signal_number_(0) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SIGNAL_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/signal_set_service.hpp b/extern/asio-1.18.2/include/asio/detail/signal_set_service.hpp new file mode 100644 index 0000000..7652fe2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/signal_set_service.hpp @@ -0,0 +1,229 @@ +// +// detail/signal_set_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP +#define ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include +#include +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/signal_handler.hpp" +#include "asio/detail/signal_op.hpp" +#include "asio/detail/socket_types.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +# include "asio/detail/reactor.hpp" +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(NSIG) && (NSIG > 0) +enum { max_signal_number = NSIG }; +#else +enum { max_signal_number = 128 }; +#endif + +extern ASIO_DECL struct signal_state* get_signal_state(); + +extern "C" ASIO_DECL void asio_signal_handler(int signal_number); + +class signal_set_service : + public execution_context_service_base +{ +public: + // Type used for tracking an individual signal registration. + class registration + { + public: + // Default constructor. + registration() + : signal_number_(0), + queue_(0), + undelivered_(0), + next_in_table_(0), + prev_in_table_(0), + next_in_set_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The signal number that is registered. + int signal_number_; + + // The waiting signal handlers. + op_queue* queue_; + + // The number of undelivered signals. + std::size_t undelivered_; + + // Pointers to adjacent registrations in the registrations_ table. + registration* next_in_table_; + registration* prev_in_table_; + + // Link to next registration in the signal set. + registration* next_in_set_; + }; + + // The implementation type of the signal_set. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : signals_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The pending signal handlers. + op_queue queue_; + + // Linked list of registered signals. + registration* signals_; + }; + + // Constructor. + ASIO_DECL signal_set_service(execution_context& context); + + // Destructor. + ASIO_DECL ~signal_set_service(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Perform fork-related housekeeping. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Construct a new signal_set implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Destroy a signal_set implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Add a signal to a signal_set. + ASIO_DECL asio::error_code add(implementation_type& impl, + int signal_number, asio::error_code& ec); + + // Remove a signal to a signal_set. + ASIO_DECL asio::error_code remove(implementation_type& impl, + int signal_number, asio::error_code& ec); + + // Remove all signals from a signal_set. + ASIO_DECL asio::error_code clear(implementation_type& impl, + asio::error_code& ec); + + // Cancel all operations associated with the signal set. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Start an asynchronous operation to wait for a signal to be delivered. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef signal_handler op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "signal_set", &impl, 0, "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + + // Deliver notification that a particular signal occurred. + ASIO_DECL static void deliver_signal(int signal_number); + +private: + // Helper function to add a service to the global signal state. + ASIO_DECL static void add_service(signal_set_service* service); + + // Helper function to remove a service from the global signal state. + ASIO_DECL static void remove_service(signal_set_service* service); + + // Helper function to create the pipe descriptors. + ASIO_DECL static void open_descriptors(); + + // Helper function to close the pipe descriptors. + ASIO_DECL static void close_descriptors(); + + // Helper function to start a wait operation. + ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op); + + // The scheduler used for dispatching handlers. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // The type used for registering for pipe reactor notifications. + class pipe_read_op; + + // The reactor used for waiting for pipe readiness. + reactor& reactor_; + + // The per-descriptor reactor data used for the pipe. + reactor::per_descriptor_data reactor_data_; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // A mapping from signal number to the registered signal sets. + registration* registrations_[max_signal_number]; + + // Pointers to adjacent services in linked list. + signal_set_service* next_; + signal_set_service* prev_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/signal_set_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/socket_holder.hpp b/extern/asio-1.18.2/include/asio/detail/socket_holder.hpp new file mode 100644 index 0000000..571b9f6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/socket_holder.hpp @@ -0,0 +1,98 @@ +// +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_HOLDER_HPP +#define ASIO_DETAIL_SOCKET_HOLDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Implement the resource acquisition is initialisation idiom for sockets. +class socket_holder + : private noncopyable +{ +public: + // Construct as an uninitialised socket. + socket_holder() + : socket_(invalid_socket) + { + } + + // Construct to take ownership of the specified socket. + explicit socket_holder(socket_type s) + : socket_(s) + { + } + + // Destructor. + ~socket_holder() + { + if (socket_ != invalid_socket) + { + asio::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + } + } + + // Get the underlying socket. + socket_type get() const + { + return socket_; + } + + // Reset to an uninitialised socket. + void reset() + { + if (socket_ != invalid_socket) + { + asio::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + socket_ = invalid_socket; + } + } + + // Reset to take ownership of the specified socket. + void reset(socket_type s) + { + reset(); + socket_ = s; + } + + // Release ownership of the socket. + socket_type release() + { + socket_type tmp = socket_; + socket_ = invalid_socket; + return tmp; + } + +private: + // The underlying socket. + socket_type socket_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/socket_ops.hpp b/extern/asio-1.18.2/include/asio/detail/socket_ops.hpp new file mode 100644 index 0000000..a37684e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/socket_ops.hpp @@ -0,0 +1,383 @@ +// +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_OPS_HPP +#define ASIO_DETAIL_SOCKET_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/error_code.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_ops { + +// Socket state bits. +enum +{ + // The user wants a non-blocking socket. + user_set_non_blocking = 1, + + // The socket has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, + + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8, + + // The socket is stream-oriented. + stream_oriented = 16, + + // The socket is datagram-oriented. + datagram_oriented = 32, + + // The socket may have been dup()-ed. + possible_dup = 64 +}; + +typedef unsigned char state_type; + +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr shared_cancel_token_type; +typedef weak_ptr weak_cancel_token_type; + +#if !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec); + +ASIO_DECL bool set_user_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL int shutdown(socket_type s, + int what, asio::error_code& ec); + +ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_connect(socket_type s, + asio::error_code& ec); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_connect(socket_type s, + asio::error_code& ec); + +ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec); + +ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec); + +ASIO_DECL size_t available(socket_type s, asio::error_code& ec); + +ASIO_DECL int listen(socket_type s, + int backlog, asio::error_code& ec); + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +ASIO_DECL void init_buf(buf& b, void* data, size_t size); + +ASIO_DECL void init_buf(buf& b, const void* data, size_t size); + +ASIO_DECL signed_size_type recv(socket_type s, buf* bufs, + size_t count, int flags, asio::error_code& ec); + +ASIO_DECL signed_size_type recv1(socket_type s, + void* data, size_t size, int flags, asio::error_code& ec); + +ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec); + +ASIO_DECL size_t sync_recv1(socket_type s, state_type state, + void* data, size_t size, int flags, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL signed_size_type recvfrom1(socket_type s, void* data, + size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state, + void* data, size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_recvfrom1(socket_type s, + void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs, + size_t count, int in_flags, int& out_flags, + asio::error_code& ec); + +ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type send(socket_type s, const buf* bufs, + size_t count, int flags, asio::error_code& ec); + +ASIO_DECL signed_size_type send1(socket_type s, + const void* data, size_t size, int flags, asio::error_code& ec); + +ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, asio::error_code& ec); + +ASIO_DECL size_t sync_send1(socket_type s, state_type state, + const void* data, size_t size, int flags, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL signed_size_type sendto1(socket_type s, const void* data, + size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_sendto1(socket_type s, state_type state, + const void* data, size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +#if !defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // !defined(ASIO_HAS_IOCP) + +ASIO_DECL socket_type socket(int af, int type, int protocol, + asio::error_code& ec); + +ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec); + +ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, asio::error_code& ec); + +ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec); + +ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL int ioctl(socket_type s, state_type& state, + int cmd, ioctl_arg_type* arg, asio::error_code& ec); + +ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec); + +ASIO_DECL int poll_read(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_write(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_error(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_connect(socket_type s, + int msec, asio::error_code& ec); + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, asio::error_code& ec); + +ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec); + +ASIO_DECL int gethostname(char* name, + int namelen, asio::error_code& ec); + +#if !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); + +ASIO_DECL asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); + +ASIO_DECL void freeaddrinfo(addrinfo_type* ai); + +ASIO_DECL asio::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, asio::error_code& ec); + +ASIO_DECL asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); + +ASIO_DECL asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL u_long_type network_to_host_long(u_long_type value); + +ASIO_DECL u_long_type host_to_network_long(u_long_type value); + +ASIO_DECL u_short_type network_to_host_short(u_short_type value); + +ASIO_DECL u_short_type host_to_network_short(u_short_type value); + +} // namespace socket_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/socket_option.hpp b/extern/asio-1.18.2/include/asio/detail/socket_option.hpp new file mode 100644 index 0000000..8d8c0d8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/socket_option.hpp @@ -0,0 +1,316 @@ +// +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_OPTION_HPP +#define ASIO_DETAIL_SOCKET_OPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_option { + +// Helper template for implementing boolean-based options. +template +class boolean +{ +public: + // Default constructor. + boolean() + : value_(0) + { + } + + // Construct with a specific option value. + explicit boolean(bool v) + : value_(v ? 1 : 0) + { + } + + // Set the current value of the boolean. + boolean& operator=(bool v) + { + value_ = v ? 1 : 0; + return *this; + } + + // Get the current value of the boolean. + bool value() const + { + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the boolean data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the boolean data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the boolean data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the boolean data. + template + void resize(const Protocol&, std::size_t s) + { + // On some platforms (e.g. Windows Vista), the getsockopt function will + // return the size of a boolean socket option as one byte, even though a + // four byte integer was passed in. + switch (s) + { + case sizeof(char): + value_ = *reinterpret_cast(&value_) ? 1 : 0; + break; + case sizeof(value_): + break; + default: + { + std::length_error ex("boolean socket option resize"); + asio::detail::throw_exception(ex); + } + } + } + +private: + int value_; +}; + +// Helper template for implementing integer options. +template +class integer +{ +public: + // Default constructor. + integer() + : value_(0) + { + } + + // Construct with a specific option value. + explicit integer(int v) + : value_(v) + { + } + + // Set the value of the int option. + integer& operator=(int v) + { + value_ = v; + return *this; + } + + // Get the current value of the int option. + int value() const + { + return value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the int data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the int data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the int data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("integer socket option resize"); + asio::detail::throw_exception(ex); + } + } + +private: + int value_; +}; + +// Helper template for implementing linger options. +template +class linger +{ +public: + // Default constructor. + linger() + { + value_.l_onoff = 0; + value_.l_linger = 0; + } + + // Construct with specific option values. + linger(bool e, int t) + { + enabled(e); + timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t); + } + + // Set the value for whether linger is enabled. + void enabled(bool value) + { + value_.l_onoff = value ? 1 : 0; + } + + // Get the value for whether linger is enabled. + bool enabled() const + { + return value_.l_onoff != 0; + } + + // Set the value for the linger timeout. + void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value) + { +#if defined(WIN32) + value_.l_linger = static_cast(value); +#else + value_.l_linger = value; +#endif + } + + // Get the value for the linger timeout. + int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const + { + return static_cast(value_.l_linger); + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the linger data. + template + detail::linger_type* data(const Protocol&) + { + return &value_; + } + + // Get the address of the linger data. + template + const detail::linger_type* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the linger data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("linger socket option resize"); + asio::detail::throw_exception(ex); + } + } + +private: + detail::linger_type value_; +}; + +} // namespace socket_option +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_OPTION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/socket_select_interrupter.hpp b/extern/asio-1.18.2/include/asio/detail/socket_select_interrupter.hpp new file mode 100644 index 0000000..2e971d2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/socket_select_interrupter.hpp @@ -0,0 +1,91 @@ +// +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class socket_select_interrupter +{ +public: + // Constructor. + ASIO_DECL socket_select_interrupter(); + + // Destructor. + ASIO_DECL ~socket_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupter. Returns true if the reset was successful. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + socket_type read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + socket_type read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + socket_type write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/socket_types.hpp b/extern/asio-1.18.2/include/asio/detail/socket_types.hpp new file mode 100644 index 0000000..33ad63e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/socket_types.hpp @@ -0,0 +1,417 @@ +// +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOCKET_TYPES_HPP +#define ASIO_DETAIL_SOCKET_TYPES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +// Empty. +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error WinSock.h has already been included +# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# if defined(__BORLANDC__) +# include // Needed for __errno +# if !defined(_WSPIAPI_H_) +# define _WSPIAPI_H_ +# define ASIO_WSPIAPI_H_DEFINED +# endif // !defined(_WSPIAPI_H_) +# endif // defined(__BORLANDC__) +# include +# include +# if defined(WINAPI_FAMILY) +# if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# include +# endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# endif // defined(WINAPI_FAMILY) +# if !defined(ASIO_WINDOWS_APP) +# include +# endif // !defined(ASIO_WINDOWS_APP) +# if defined(ASIO_WSPIAPI_H_DEFINED) +# undef _WSPIAPI_H_ +# undef ASIO_WSPIAPI_H_DEFINED +# endif // defined(ASIO_WSPIAPI_H_DEFINED) +# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) +# pragma comment(lib, "ws2_32.lib") +# if !defined(ASIO_WINDOWS_APP) +# pragma comment(lib, "mswsock.lib") +# endif // !defined(ASIO_WINDOWS_APP) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# include "asio/detail/old_win_sdk_compat.hpp" +#else +# include +# if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) || defined(__NetBSD__) \ + || defined(__OpenBSD__) || defined(__linux__) \ + || defined(__EMSCRIPTEN__) +# include +# elif !defined(__SYMBIAN32__) +# include +# endif +# include +# include +# include +# if defined(__hpux) +# include +# endif +# if !defined(__hpux) || defined(__SELECT) +# include +# endif +# include +# include +# include +# include +# if !defined(__SYMBIAN32__) +# include +# endif +# include +# include +# include +# include +# if defined(__sun) +# include +# include +# endif +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS_RUNTIME) +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef unsigned __int32 u_long_type; +typedef unsigned __int16 u_short_type; +struct in4_addr_type { u_long_type s_addr; }; +struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; }; +struct in6_addr_type { unsigned char s6_addr[16]; }; +struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr; + unsigned long ipv6mr_interface; }; +struct socket_addr_type { int sa_family; }; +struct sockaddr_in4_type { int sin_family; + in4_addr_type sin_addr; u_short_type sin_port; }; +struct sockaddr_in6_type { int sin6_family; + in6_addr_type sin6_addr; u_short_type sin6_port; + u_long_type sin6_flowinfo; u_long_type sin6_scope_id; }; +struct sockaddr_storage_type { int ss_family; + unsigned char ss_bytes[128 - sizeof(int)]; }; +struct addrinfo_type { int ai_flags; + int ai_family, ai_socktype, ai_protocol; + int ai_addrlen; const void* ai_addr; + const char* ai_canonname; addrinfo_type* ai_next; }; +struct linger_type { u_short_type l_onoff, l_linger; }; +typedef u_long_type ioctl_arg_type; +typedef int signed_size_type; +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC 0 +# define ASIO_OS_DEF_AF_INET 2 +# define ASIO_OS_DEF_AF_INET6 23 +# define ASIO_OS_DEF_SOCK_STREAM 1 +# define ASIO_OS_DEF_SOCK_DGRAM 2 +# define ASIO_OS_DEF_SOCK_RAW 3 +# define ASIO_OS_DEF_SOCK_SEQPACKET 5 +# define ASIO_OS_DEF_IPPROTO_IP 0 +# define ASIO_OS_DEF_IPPROTO_IPV6 41 +# define ASIO_OS_DEF_IPPROTO_TCP 6 +# define ASIO_OS_DEF_IPPROTO_UDP 17 +# define ASIO_OS_DEF_IPPROTO_ICMP 1 +# define ASIO_OS_DEF_IPPROTO_ICMPV6 58 +# define ASIO_OS_DEF_FIONBIO 1 +# define ASIO_OS_DEF_FIONREAD 2 +# define ASIO_OS_DEF_INADDR_ANY 0 +# define ASIO_OS_DEF_MSG_OOB 0x1 +# define ASIO_OS_DEF_MSG_PEEK 0x2 +# define ASIO_OS_DEF_MSG_DONTROUTE 0x4 +# define ASIO_OS_DEF_MSG_EOR 0 // Not supported. +# define ASIO_OS_DEF_SHUT_RD 0x0 +# define ASIO_OS_DEF_SHUT_WR 0x1 +# define ASIO_OS_DEF_SHUT_RDWR 0x2 +# define ASIO_OS_DEF_SOMAXCONN 0x7fffffff +# define ASIO_OS_DEF_SOL_SOCKET 0xffff +# define ASIO_OS_DEF_SO_BROADCAST 0x20 +# define ASIO_OS_DEF_SO_DEBUG 0x1 +# define ASIO_OS_DEF_SO_DONTROUTE 0x10 +# define ASIO_OS_DEF_SO_KEEPALIVE 0x8 +# define ASIO_OS_DEF_SO_LINGER 0x80 +# define ASIO_OS_DEF_SO_OOBINLINE 0x100 +# define ASIO_OS_DEF_SO_SNDBUF 0x1001 +# define ASIO_OS_DEF_SO_RCVBUF 0x1002 +# define ASIO_OS_DEF_SO_SNDLOWAT 0x1003 +# define ASIO_OS_DEF_SO_RCVLOWAT 0x1004 +# define ASIO_OS_DEF_SO_REUSEADDR 0x4 +# define ASIO_OS_DEF_TCP_NODELAY 0x1 +# define ASIO_OS_DEF_IP_MULTICAST_IF 2 +# define ASIO_OS_DEF_IP_MULTICAST_TTL 3 +# define ASIO_OS_DEF_IP_MULTICAST_LOOP 4 +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5 +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6 +# define ASIO_OS_DEF_IP_TTL 7 +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS 4 +# define ASIO_OS_DEF_IPV6_MULTICAST_IF 9 +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10 +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11 +# define ASIO_OS_DEF_IPV6_JOIN_GROUP 12 +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP 13 +# define ASIO_OS_DEF_AI_CANONNAME 0x2 +# define ASIO_OS_DEF_AI_PASSIVE 0x1 +# define ASIO_OS_DEF_AI_NUMERICHOST 0x4 +# define ASIO_OS_DEF_AI_NUMERICSERV 0x8 +# define ASIO_OS_DEF_AI_V4MAPPED 0x800 +# define ASIO_OS_DEF_AI_ALL 0x100 +# define ASIO_OS_DEF_AI_ADDRCONFIG 0x400 +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef SOCKET socket_type; +const SOCKET invalid_socket = INVALID_SOCKET; +const int socket_error_retval = SOCKET_ERROR; +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +typedef ip_mreq in4_mreq_type; +typedef sockaddr_in sockaddr_in4_type; +# if defined(ASIO_HAS_OLD_WIN_SDK) +typedef in6_addr_emulation in6_addr_type; +typedef ipv6_mreq_emulation in6_mreq_type; +typedef sockaddr_in6_emulation sockaddr_in6_type; +typedef sockaddr_storage_emulation sockaddr_storage_type; +typedef addrinfo_emulation addrinfo_type; +# else +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef addrinfo addrinfo_type; +# endif +typedef ::linger linger_type; +typedef unsigned long ioctl_arg_type; +typedef u_long u_long_type; +typedef u_short u_short_type; +typedef int signed_size_type; +struct sockaddr_un_type { u_short sun_family; char sun_path[108]; }; +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define ASIO_OS_DEF_AF_INET AF_INET +# define ASIO_OS_DEF_AF_INET6 AF_INET6 +# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define ASIO_OS_DEF_FIONBIO FIONBIO +# define ASIO_OS_DEF_FIONREAD FIONREAD +# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define ASIO_OS_DEF_MSG_OOB MSG_OOB +# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows. +# define ASIO_OS_DEF_SHUT_RD SD_RECEIVE +# define ASIO_OS_DEF_SHUT_WR SD_SEND +# define ASIO_OS_DEF_SHUT_RDWR SD_BOTH +# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define ASIO_OS_DEF_IP_TTL IP_TTL +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define ASIO_OS_DEF_AI_NUMERICSERV 0 +# endif +# if defined(AI_V4MAPPED) +# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) +# define ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) +# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined (_WIN32_WINNT) +const int max_iov_len = 64; +# else +const int max_iov_len = 16; +# endif +#else +typedef int socket_type; +const int invalid_socket = -1; +const int socket_error_retval = -1; +const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#if defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; +#else // defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = 256; +#endif // defined(INET6_ADDRSTRLEN) +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +# if defined(__hpux) +// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. +struct in4_mreq_type +{ + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; +# else +typedef ip_mreq in4_mreq_type; +# endif +typedef sockaddr_in sockaddr_in4_type; +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef sockaddr_un sockaddr_un_type; +typedef addrinfo addrinfo_type; +typedef ::linger linger_type; +typedef int ioctl_arg_type; +typedef uint32_t u_long_type; +typedef uint16_t u_short_type; +#if defined(ASIO_HAS_SSIZE_T) +typedef ssize_t signed_size_type; +#else // defined(ASIO_HAS_SSIZE_T) +typedef int signed_size_type; +#endif // defined(ASIO_HAS_SSIZE_T) +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define ASIO_OS_DEF_AF_INET AF_INET +# define ASIO_OS_DEF_AF_INET6 AF_INET6 +# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define ASIO_OS_DEF_FIONBIO FIONBIO +# define ASIO_OS_DEF_FIONREAD FIONREAD +# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define ASIO_OS_DEF_MSG_OOB MSG_OOB +# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define ASIO_OS_DEF_MSG_EOR MSG_EOR +# define ASIO_OS_DEF_SHUT_RD SHUT_RD +# define ASIO_OS_DEF_SHUT_WR SHUT_WR +# define ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR +# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define ASIO_OS_DEF_IP_TTL IP_TTL +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define ASIO_OS_DEF_AI_NUMERICSERV 0 +# endif +// Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but +// does not implement them. Therefore they are specifically excluded here. +# if defined(AI_V4MAPPED) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined(IOV_MAX) +const int max_iov_len = IOV_MAX; +# else +// POSIX platforms are not required to define IOV_MAX. +const int max_iov_len = 16; +# endif +#endif +const int custom_socket_option_level = 0xA5100000; +const int enable_connection_aborted_option = 1; +const int always_fail_option = 2; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_TYPES_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/solaris_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/solaris_fenced_block.hpp new file mode 100644 index 0000000..4f6640b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/solaris_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP +#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__sun) + +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class solaris_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit solaris_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit solaris_fenced_block(full_t) + { + membar_consumer(); + } + + // Destructor. + ~solaris_fenced_block() + { + membar_producer(); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__sun) + +#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/source_location.hpp b/extern/asio-1.18.2/include/asio/detail/source_location.hpp new file mode 100644 index 0000000..a9ac8e8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/source_location.hpp @@ -0,0 +1,45 @@ +// +// detail/source_location.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_SOURCE_LOCATION_HPP +#define ASIO_DETAIL_SOURCE_LOCATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SOURCE_LOCATION) + +#if defined(ASIO_HAS_STD_SOURCE_LOCATION) +# include +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# include +#else // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# error ASIO_HAS_SOURCE_LOCATION is set \ + but no source_location is available +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_SOURCE_LOCATION) +using std::source_location; +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +using std::experimental::source_location; +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +} // namespace detail +} // namespace asio + +#endif // defined(ASIO_HAS_SOURCE_LOCATION) + +#endif // ASIO_DETAIL_SOURCE_LOCATION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/static_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/static_mutex.hpp new file mode 100644 index 0000000..5876a99 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/static_mutex.hpp @@ -0,0 +1,52 @@ +// +// detail/static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STATIC_MUTEX_HPP +#define ASIO_DETAIL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_static_mutex.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_static_mutex.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_static_mutex.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_static_mutex.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_NULL_STATIC_MUTEX_INIT +#elif defined(ASIO_WINDOWS) +typedef win_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_WIN_STATIC_MUTEX_INIT +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_STATIC_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_event.hpp b/extern/asio-1.18.2/include/asio/detail/std_event.hpp new file mode 100644 index 0000000..1fc5177 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_event.hpp @@ -0,0 +1,188 @@ +// +// detail/std_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_EVENT_HPP +#define ASIO_DETAIL_STD_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event + : private noncopyable +{ +public: + // Constructor. + std_event() + : state_(0) + { + } + + // Destructor. + ~std_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + cond_.notify_all(); + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + cond_.notify_one(); + } + + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + cond_.notify_one(); + lock.unlock(); + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + cond_.notify_one(); + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + while ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait(u_lock.unique_lock_); + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + if ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec)); + } + return (state_ & 1) != 0; + } + +private: + // Helper class to temporarily adapt a scoped_lock into a unique_lock so that + // it can be passed to std::condition_variable::wait(). + struct unique_lock_adapter + { + template + explicit unique_lock_adapter(Lock& lock) + : unique_lock_(lock.mutex().mutex_, std::adopt_lock) + { + } + + ~unique_lock_adapter() + { + unique_lock_.release(); + } + + std::unique_lock unique_lock_; + }; + + // Helper to increment and decrement the state to track outstanding waiters. + class waiter + { + public: + explicit waiter(std::size_t& state) + : state_(state) + { + state_ += 2; + } + + ~waiter() + { + state_ -= 2; + } + + private: + std::size_t& state_; + }; + + std::condition_variable cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/std_fenced_block.hpp new file mode 100644 index 0000000..2361b17 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/std_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_FENCED_BLOCK_HPP +#define ASIO_DETAIL_STD_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_ATOMIC) + +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit std_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit std_fenced_block(full_t) + { + std::atomic_thread_fence(std::memory_order_acquire); + } + + // Destructor. + ~std_fenced_block() + { + std::atomic_thread_fence(std::memory_order_release); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_ATOMIC) + +#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_global.hpp b/extern/asio-1.18.2/include/asio/detail/std_global.hpp new file mode 100644 index 0000000..cdb3062 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_global.hpp @@ -0,0 +1,70 @@ +// +// detail/std_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_GLOBAL_HPP +#define ASIO_DETAIL_STD_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_CALL_ONCE) + +#include +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct std_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~std_global_impl() + { + delete ptr_; + } + + static std::once_flag init_once_; + static std_global_impl instance_; + T* ptr_; +}; + +template +std::once_flag std_global_impl::init_once_; + +template +std_global_impl std_global_impl::instance_; + +template +T& std_global() +{ + std::call_once(std_global_impl::init_once_, &std_global_impl::do_init); + return *std_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_CALL_ONCE) + +#endif // ASIO_DETAIL_STD_GLOBAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/std_mutex.hpp new file mode 100644 index 0000000..37471be --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_mutex.hpp @@ -0,0 +1,73 @@ +// +// detail/std_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_MUTEX_HPP +#define ASIO_DETAIL_STD_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event; + +class std_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock scoped_lock; + + // Constructor. + std_mutex() + { + } + + // Destructor. + ~std_mutex() + { + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_static_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/std_static_mutex.hpp new file mode 100644 index 0000000..ce14133 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_static_mutex.hpp @@ -0,0 +1,81 @@ +// +// detail/std_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_STATIC_MUTEX_HPP +#define ASIO_DETAIL_STD_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event; + +class std_static_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock scoped_lock; + + // Constructor. + std_static_mutex(int) + { + } + + // Destructor. + ~std_static_mutex() + { + } + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +#define ASIO_STD_STATIC_MUTEX_INIT 0 + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/std_thread.hpp b/extern/asio-1.18.2/include/asio/detail/std_thread.hpp new file mode 100644 index 0000000..00cd4c9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/std_thread.hpp @@ -0,0 +1,71 @@ +// +// detail/std_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STD_THREAD_HPP +#define ASIO_DETAIL_STD_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_THREAD) + +#include +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_thread + : private noncopyable +{ +public: + // Constructor. + template + std_thread(Function f, unsigned int = 0) + : thread_(f) + { + } + + // Destructor. + ~std_thread() + { + join(); + } + + // Wait for the thread to exit. + void join() + { + if (thread_.joinable()) + thread_.join(); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return std::thread::hardware_concurrency(); + } + +private: + std::thread thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_THREAD) + +#endif // ASIO_DETAIL_STD_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/strand_executor_service.hpp b/extern/asio-1.18.2/include/asio/detail/strand_executor_service.hpp new file mode 100644 index 0000000..cdbea6b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/strand_executor_service.hpp @@ -0,0 +1,173 @@ +// +// detail/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP +#define ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/executor_op.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_executor_service + : public execution_context_service_base +{ +public: + // The underlying implementation of a strand. + class strand_impl + { + public: + ASIO_DECL ~strand_impl(); + + private: + friend class strand_executor_service; + + // Mutex to protect access to internal data. + mutex* mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // Indicates that the strand has been shut down and will accept no further + // handlers. + bool shutdown_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue ready_queue_; + + // Pointers to adjacent handle implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The strand service in where the implementation is held. + strand_executor_service* service_; + }; + + typedef shared_ptr implementation_type; + + // Construct a new strand service for the specified context. + ASIO_DECL explicit strand_executor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Create a new strand_executor implementation. + ASIO_DECL implementation_type create_implementation(); + + // Request invocation of the given function. + template + static void execute(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, + typename enable_if< + can_query >::value + >::type* = 0); + + // Request invocation of the given function. + template + static void execute(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, + typename enable_if< + !can_query >::value + >::type* = 0); + + // Request invocation of the given function. + template + static void dispatch(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template + static void post(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template + static void defer(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Determine whether the strand is running in the current thread. + ASIO_DECL static bool running_in_this_thread( + const implementation_type& impl); + +private: + friend class strand_impl; + template class allocator_binder; + template class invoker; + + // Adds a function to the strand. Returns true if it acquires the lock. + ASIO_DECL static bool enqueue(const implementation_type& impl, + scheduler_operation* op); + + // Transfers waiting handlers to the ready queue. Returns true if one or more + // handlers were transferred. + ASIO_DECL static bool push_waiting_to_ready(implementation_type& impl); + + // Invokes all ready-to-run handlers. + ASIO_DECL static void run_ready_handlers(implementation_type& impl); + + // Helper function to request invocation of the given function. + template + static void do_execute(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Mutex to protect access to the service-wide state. + mutex mutex_; + + // Number of mutexes shared between all strand objects. + enum { num_mutexes = 193 }; + + // Pool of mutexes. + scoped_ptr mutexes_[num_mutexes]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same mutex. + std::size_t salt_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/strand_executor_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/strand_executor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/strand_service.hpp b/extern/asio-1.18.2/include/asio/detail/strand_service.hpp new file mode 100644 index 0000000..2aec8e5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/strand_service.hpp @@ -0,0 +1,144 @@ +// +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STRAND_SERVICE_HPP +#define ASIO_DETAIL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/scoped_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_service + : public asio::detail::service_base +{ +private: + // Helper class to re-post the strand on exit. + struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. + struct on_dispatch_exit; + +public: + + // The underlying implementation of a strand. + class strand_impl + : public operation + { + public: + strand_impl(); + + private: + // Only this service will have access to the internal values. + friend class strand_service; + friend struct on_do_complete_exit; + friend struct on_dispatch_exit; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue ready_queue_; + }; + + typedef strand_impl* implementation_type; + + // Construct a new strand service for the specified io_context. + ASIO_DECL explicit strand_service(asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new strand implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Request the io_context to invoke the given handler. + template + void dispatch(implementation_type& impl, Handler& handler); + + // Request the io_context to invoke the given handler and return immediately. + template + void post(implementation_type& impl, Handler& handler); + + // Determine whether the strand is running in the current thread. + ASIO_DECL bool running_in_this_thread( + const implementation_type& impl) const; + +private: + // Helper function to dispatch a handler. + ASIO_DECL void do_dispatch(implementation_type& impl, operation* op); + + // Helper function to post a handler. + ASIO_DECL void do_post(implementation_type& impl, + operation* op, bool is_continuation); + + ASIO_DECL static void do_complete(void* owner, + operation* base, const asio::error_code& ec, + std::size_t bytes_transferred); + + // The io_context used to obtain an I/O executor. + io_context& io_context_; + + // The io_context implementation used to post completions. + io_context_impl& io_context_impl_; + + // Mutex to protect access to the array of implementations. + asio::detail::mutex mutex_; + + // Number of implementations shared between all strand objects. +#if defined(ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = ASIO_STRAND_IMPLEMENTATIONS }; +#else // defined(ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = 193 }; +#endif // defined(ASIO_STRAND_IMPLEMENTATIONS) + + // Pool of implementations. + scoped_ptr implementations_[num_implementations]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same strand implementation. + std::size_t salt_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/strand_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/strand_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/string_view.hpp b/extern/asio-1.18.2/include/asio/detail/string_view.hpp new file mode 100644 index 0000000..488e9aa --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/string_view.hpp @@ -0,0 +1,47 @@ +// +// detail/string_view.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_STRING_VIEW_HPP +#define ASIO_DETAIL_STRING_VIEW_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STRING_VIEW) + +#if defined(ASIO_HAS_STD_STRING_VIEW) +# include +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# include +#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# error ASIO_HAS_STRING_VIEW is set but no string_view is available +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +namespace asio { + +#if defined(ASIO_HAS_STD_STRING_VIEW) +using std::basic_string_view; +using std::string_view; +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::experimental::basic_string_view; +using std::experimental::string_view; +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +} // namespace asio + +# define ASIO_STRING_VIEW_PARAM asio::string_view +#else // defined(ASIO_HAS_STRING_VIEW) +# define ASIO_STRING_VIEW_PARAM const std::string& +#endif // defined(ASIO_HAS_STRING_VIEW) + +#endif // ASIO_DETAIL_STRING_VIEW_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/thread.hpp b/extern/asio-1.18.2/include/asio/detail/thread.hpp new file mode 100644 index 0000000..8d1b662 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/thread.hpp @@ -0,0 +1,60 @@ +// +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THREAD_HPP +#define ASIO_DETAIL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_thread.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_thread.hpp" +#elif defined(ASIO_WINDOWS) +# if defined(UNDER_CE) +# include "asio/detail/wince_thread.hpp" +# elif defined(ASIO_WINDOWS_APP) +# include "asio/detail/winapp_thread.hpp" +# else +# include "asio/detail/win_thread.hpp" +# endif +#elif defined(ASIO_HAS_STD_THREAD) +# include "asio/detail/std_thread.hpp" +#else +# error Only Windows, POSIX and std::thread are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_thread thread; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_thread thread; +#elif defined(ASIO_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# elif defined(ASIO_WINDOWS_APP) +typedef winapp_thread thread; +# else +typedef win_thread thread; +# endif +#elif defined(ASIO_HAS_STD_THREAD) +typedef std_thread thread; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/thread_context.hpp b/extern/asio-1.18.2/include/asio/detail/thread_context.hpp new file mode 100644 index 0000000..f178241 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/thread_context.hpp @@ -0,0 +1,51 @@ +// +// detail/thread_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THREAD_CONTEXT_HPP +#define ASIO_DETAIL_THREAD_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include "asio/detail/call_stack.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_info_base; + +// Base class for things that manage threads (scheduler, win_iocp_io_context). +class thread_context +{ +public: + // Obtain a pointer to the top of the thread call stack. Returns null when + // not running inside a thread context. + ASIO_DECL static thread_info_base* top_of_thread_call_stack(); + +protected: + // Per-thread call stack to track the state of each thread in the context. + typedef call_stack thread_call_stack; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/thread_context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_THREAD_CONTEXT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/thread_group.hpp b/extern/asio-1.18.2/include/asio/detail/thread_group.hpp new file mode 100644 index 0000000..11965f5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/thread_group.hpp @@ -0,0 +1,99 @@ +// +// detail/thread_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THREAD_GROUP_HPP +#define ASIO_DETAIL_THREAD_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/thread.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_group +{ +public: + // Constructor initialises an empty thread group. + thread_group() + : first_(0) + { + } + + // Destructor joins any remaining threads in the group. + ~thread_group() + { + join(); + } + + // Create a new thread in the group. + template + void create_thread(Function f) + { + first_ = new item(f, first_); + } + + // Create new threads in the group. + template + void create_threads(Function f, std::size_t num_threads) + { + for (std::size_t i = 0; i < num_threads; ++i) + create_thread(f); + } + + // Wait for all threads in the group to exit. + void join() + { + while (first_) + { + first_->thread_.join(); + item* tmp = first_; + first_ = first_->next_; + delete tmp; + } + } + + // Test whether the group is empty. + bool empty() const + { + return first_ == 0; + } + +private: + // Structure used to track a single thread in the group. + struct item + { + template + explicit item(Function f, item* next) + : thread_(f), + next_(next) + { + } + + asio::detail::thread thread_; + item* next_; + }; + + // The first thread in the group. + item* first_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THREAD_GROUP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/thread_info_base.hpp b/extern/asio-1.18.2/include/asio/detail/thread_info_base.hpp new file mode 100644 index 0000000..6431b64 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/thread_info_base.hpp @@ -0,0 +1,190 @@ +// +// detail/thread_info_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THREAD_INFO_BASE_HPP +#define ASIO_DETAIL_THREAD_INFO_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/detail/noncopyable.hpp" + +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(ASIO_NO_EXCEPTIONS) +# include +# include "asio/multiple_exceptions.hpp" +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(ASIO_NO_EXCEPTIONS) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_info_base + : private noncopyable +{ +public: + struct default_tag + { + enum { mem_index = 0 }; + }; + + struct awaitable_frame_tag + { + enum { mem_index = 1 }; + }; + + struct executor_function_tag + { + enum { mem_index = 2 }; + }; + + thread_info_base() +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(ASIO_NO_EXCEPTIONS) + : has_pending_exception_(0) +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(ASIO_NO_EXCEPTIONS) + { + for (int i = 0; i < max_mem_index; ++i) + reusable_memory_[i] = 0; + } + + ~thread_info_base() + { + for (int i = 0; i < max_mem_index; ++i) + { + // The following test for non-null pointers is technically redundant, but + // it is significantly faster when using a tight io_context::poll() loop + // in latency sensitive applications. + if (reusable_memory_[i]) + ::operator delete(reusable_memory_[i]); + } + } + + static void* allocate(thread_info_base* this_thread, std::size_t size) + { + return allocate(default_tag(), this_thread, size); + } + + static void deallocate(thread_info_base* this_thread, + void* pointer, std::size_t size) + { + deallocate(default_tag(), this_thread, pointer, size); + } + + template + static void* allocate(Purpose, thread_info_base* this_thread, + std::size_t size) + { + std::size_t chunks = (size + chunk_size - 1) / chunk_size; + + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) + { + void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; + this_thread->reusable_memory_[Purpose::mem_index] = 0; + + unsigned char* const mem = static_cast(pointer); + if (static_cast(mem[0]) >= chunks) + { + mem[size] = mem[0]; + return pointer; + } + + ::operator delete(pointer); + } + + void* const pointer = ::operator new(chunks * chunk_size + 1); + unsigned char* const mem = static_cast(pointer); + mem[size] = (chunks <= UCHAR_MAX) ? static_cast(chunks) : 0; + return pointer; + } + + template + static void deallocate(Purpose, thread_info_base* this_thread, + void* pointer, std::size_t size) + { + if (size <= chunk_size * UCHAR_MAX) + { + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) + { + unsigned char* const mem = static_cast(pointer); + mem[0] = mem[size]; + this_thread->reusable_memory_[Purpose::mem_index] = pointer; + return; + } + } + + ::operator delete(pointer); + } + + void capture_current_exception() + { +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(ASIO_NO_EXCEPTIONS) + switch (has_pending_exception_) + { + case 0: + has_pending_exception_ = 1; + pending_exception_ = std::current_exception(); + break; + case 1: + has_pending_exception_ = 2; + pending_exception_ = + std::make_exception_ptr( + multiple_exceptions(pending_exception_)); + break; + default: + break; + } +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(ASIO_NO_EXCEPTIONS) + } + + void rethrow_pending_exception() + { +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(ASIO_NO_EXCEPTIONS) + if (has_pending_exception_ > 0) + { + has_pending_exception_ = 0; + std::exception_ptr ex( + ASIO_MOVE_CAST(std::exception_ptr)( + pending_exception_)); + std::rethrow_exception(ex); + } +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(ASIO_NO_EXCEPTIONS) + } + +private: + enum { chunk_size = 4 }; + enum { max_mem_index = 3 }; + void* reusable_memory_[max_mem_index]; + +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(ASIO_NO_EXCEPTIONS) + int has_pending_exception_; + std::exception_ptr pending_exception_; +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(ASIO_NO_EXCEPTIONS) +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/throw_error.hpp b/extern/asio-1.18.2/include/asio/detail/throw_error.hpp new file mode 100644 index 0000000..d03cad5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/throw_error.hpp @@ -0,0 +1,53 @@ +// +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THROW_ERROR_HPP +#define ASIO_DETAIL_THROW_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +ASIO_DECL void do_throw_error(const asio::error_code& err); + +ASIO_DECL void do_throw_error(const asio::error_code& err, + const char* location); + +inline void throw_error(const asio::error_code& err) +{ + if (err) + do_throw_error(err); +} + +inline void throw_error(const asio::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/throw_error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_THROW_ERROR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/throw_exception.hpp b/extern/asio-1.18.2/include/asio/detail/throw_exception.hpp new file mode 100644 index 0000000..bbee22a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/throw_exception.hpp @@ -0,0 +1,51 @@ +// +// detail/throw_exception.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_THROW_EXCEPTION_HPP +#define ASIO_DETAIL_THROW_EXCEPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +# include +#endif // defined(ASIO_BOOST_THROW_EXCEPTION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +using boost::throw_exception; +#else // defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Declare the throw_exception function for all targets. +template +void throw_exception(const Exception& e); + +// Only define the throw_exception function when exceptions are enabled. +// Otherwise, it is up to the application to provide a definition of this +// function. +# if !defined(ASIO_NO_EXCEPTIONS) +template +void throw_exception(const Exception& e) +{ + throw e; +} +# endif // !defined(ASIO_NO_EXCEPTIONS) + +#endif // defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_THROW_EXCEPTION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_queue.hpp b/extern/asio-1.18.2/include/asio/detail/timer_queue.hpp new file mode 100644 index 0000000..d336869 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_queue.hpp @@ -0,0 +1,360 @@ +// +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_QUEUE_HPP +#define ASIO_DETAIL_TIMER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/detail/cstdint.hpp" +#include "asio/detail/date_time_fwd.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class timer_queue + : public timer_queue_base +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // Per-timer data. + class per_timer_data + { + public: + per_timer_data() : + heap_index_((std::numeric_limits::max)()), + next_(0), prev_(0) + { + } + + private: + friend class timer_queue; + + // The operations waiting on the timer. + op_queue op_queue_; + + // The index of the timer in the heap. + std::size_t heap_index_; + + // Pointers to adjacent timers in a linked list. + per_timer_data* next_; + per_timer_data* prev_; + }; + + // Constructor. + timer_queue() + : timers_(), + heap_() + { + } + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op) + { + // Enqueue the timer object. + if (timer.prev_ == 0 && &timer != timers_) + { + if (this->is_positive_infinity(time)) + { + // No heap entry is required for timers that never expire. + timer.heap_index_ = (std::numeric_limits::max)(); + } + else + { + // Put the new timer at the correct position in the heap. This is done + // first since push_back() can throw due to allocation failure. + timer.heap_index_ = heap_.size(); + heap_entry entry = { time, &timer }; + heap_.push_back(entry); + up_heap(heap_.size() - 1); + } + + // Insert the new timer into the linked list of active timers. + timer.next_ = timers_; + timer.prev_ = 0; + if (timers_) + timers_->prev_ = &timer; + timers_ = &timer; + } + + // Enqueue the individual timer operation. + timer.op_queue_.push(op); + + // Interrupt reactor only if newly added timer is first to expire. + return timer.heap_index_ == 0 && timer.op_queue_.front() == op; + } + + // Whether there are no timers in the queue. + virtual bool empty() const + { + return timers_ == 0; + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_msec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_msec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_usec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_usec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Dequeue all timers not later than the current time. + virtual void get_ready_timers(op_queue& ops) + { + if (!heap_.empty()) + { + const time_type now = Time_Traits::now(); + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) + { + per_timer_data* timer = heap_[0].timer_; + ops.push(timer->op_queue_); + remove_timer(*timer); + } + } + } + + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) + { + while (timers_) + { + per_timer_data* timer = timers_; + timers_ = timers_->next_; + ops.push(timer->op_queue_); + timer->next_ = 0; + timer->prev_ = 0; + } + + heap_.clear(); + } + + // Cancel and dequeue operations for the given timer. + std::size_t cancel_timer(per_timer_data& timer, op_queue& ops, + std::size_t max_cancelled = (std::numeric_limits::max)()) + { + std::size_t num_cancelled = 0; + if (timer.prev_ != 0 || &timer == timers_) + { + while (wait_op* op = (num_cancelled != max_cancelled) + ? timer.op_queue_.front() : 0) + { + op->ec_ = asio::error::operation_aborted; + timer.op_queue_.pop(); + ops.push(op); + ++num_cancelled; + } + if (timer.op_queue_.empty()) + remove_timer(timer); + } + return num_cancelled; + } + + // Move operations from one timer to another, empty timer. + void move_timer(per_timer_data& target, per_timer_data& source) + { + target.op_queue_.push(source.op_queue_); + + target.heap_index_ = source.heap_index_; + source.heap_index_ = (std::numeric_limits::max)(); + + if (target.heap_index_ < heap_.size()) + heap_[target.heap_index_].timer_ = ⌖ + + if (timers_ == &source) + timers_ = ⌖ + if (source.prev_) + source.prev_->next_ = ⌖ + if (source.next_) + source.next_->prev_= ⌖ + target.next_ = source.next_; + target.prev_ = source.prev_; + source.next_ = 0; + source.prev_ = 0; + } + +private: + // Move the item at the given index up the heap to its correct position. + void up_heap(std::size_t index) + { + while (index > 0) + { + std::size_t parent = (index - 1) / 2; + if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_)) + break; + swap_heap(index, parent); + index = parent; + } + } + + // Move the item at the given index down the heap to its correct position. + void down_heap(std::size_t index) + { + std::size_t child = index * 2 + 1; + while (child < heap_.size()) + { + std::size_t min_child = (child + 1 == heap_.size() + || Time_Traits::less_than( + heap_[child].time_, heap_[child + 1].time_)) + ? child : child + 1; + if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_)) + break; + swap_heap(index, min_child); + index = min_child; + child = index * 2 + 1; + } + } + + // Swap two entries in the heap. + void swap_heap(std::size_t index1, std::size_t index2) + { + heap_entry tmp = heap_[index1]; + heap_[index1] = heap_[index2]; + heap_[index2] = tmp; + heap_[index1].timer_->heap_index_ = index1; + heap_[index2].timer_->heap_index_ = index2; + } + + // Remove a timer from the heap and list of timers. + void remove_timer(per_timer_data& timer) + { + // Remove the timer from the heap. + std::size_t index = timer.heap_index_; + if (!heap_.empty() && index < heap_.size()) + { + if (index == heap_.size() - 1) + { + timer.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + } + else + { + swap_heap(index, heap_.size() - 1); + timer.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + if (index > 0 && Time_Traits::less_than( + heap_[index].time_, heap_[(index - 1) / 2].time_)) + up_heap(index); + else + down_heap(index); + } + } + + // Remove the timer from the linked list of active timers. + if (timers_ == &timer) + timers_ = timer.next_; + if (timer.prev_) + timer.prev_->next_ = timer.next_; + if (timer.next_) + timer.next_->prev_= timer.prev_; + timer.next_ = 0; + timer.prev_ = 0; + } + + // Determine if the specified absolute time is positive infinity. + template + static bool is_positive_infinity(const Time_Type&) + { + return false; + } + + // Determine if the specified absolute time is positive infinity. + template + static bool is_positive_infinity( + const boost::date_time::base_time& time) + { + return time.is_pos_infinity(); + } + + // Helper function to convert a duration into milliseconds. + template + long to_msec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t msec = d.total_milliseconds(); + if (msec == 0) + return 1; + if (msec > max_duration) + return max_duration; + return static_cast(msec); + } + + // Helper function to convert a duration into microseconds. + template + long to_usec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t usec = d.total_microseconds(); + if (usec == 0) + return 1; + if (usec > max_duration) + return max_duration; + return static_cast(usec); + } + + // The head of a linked list of all active timers. + per_timer_data* timers_; + + struct heap_entry + { + // The time when the timer should fire. + time_type time_; + + // The associated timer with enqueued operations. + per_timer_data* timer_; + }; + + // The heap of timers, with the earliest timer at the front. + std::vector heap_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TIMER_QUEUE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_queue_base.hpp b/extern/asio-1.18.2/include/asio/detail/timer_queue_base.hpp new file mode 100644 index 0000000..7ab2e6d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_queue_base.hpp @@ -0,0 +1,68 @@ +// +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_QUEUE_BASE_HPP +#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class timer_queue_base + : private noncopyable +{ +public: + // Constructor. + timer_queue_base() : next_(0) {} + + // Destructor. + virtual ~timer_queue_base() {} + + // Whether there are no timers in the queue. + virtual bool empty() const = 0; + + // Get the time to wait until the next timer. + virtual long wait_duration_msec(long max_duration) const = 0; + + // Get the time to wait until the next timer. + virtual long wait_duration_usec(long max_duration) const = 0; + + // Dequeue all ready timers. + virtual void get_ready_timers(op_queue& ops) = 0; + + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) = 0; + +private: + friend class timer_queue_set; + + // Next timer queue in the set. + timer_queue_base* next_; +}; + +template +class timer_queue; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_queue_ptime.hpp b/extern/asio-1.18.2/include/asio/detail/timer_queue_ptime.hpp new file mode 100644 index 0000000..dfdacd1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_queue_ptime.hpp @@ -0,0 +1,99 @@ +// +// detail/timer_queue_ptime.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP +#define ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) + +#include "asio/time_traits.hpp" +#include "asio/detail/timer_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct forwarding_posix_time_traits : time_traits {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Per-timer data. + typedef timer_queue::per_timer_data + per_timer_data; + + // Constructor. + ASIO_DECL timer_queue(); + + // Destructor. + ASIO_DECL virtual ~timer_queue(); + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + ASIO_DECL bool enqueue_timer(const time_type& time, + per_timer_data& timer, wait_op* op); + + // Whether there are no timers in the queue. + ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + ASIO_DECL virtual void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + ASIO_DECL virtual void get_all_timers(op_queue& ops); + + // Cancel and dequeue operations for the given timer. + ASIO_DECL std::size_t cancel_timer( + per_timer_data& timer, op_queue& ops, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move operations from one timer to another, empty timer. + ASIO_DECL void move_timer(per_timer_data& target, + per_timer_data& source); + +private: + timer_queue impl_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/timer_queue_ptime.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#endif // ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_queue_set.hpp b/extern/asio-1.18.2/include/asio/detail/timer_queue_set.hpp new file mode 100644 index 0000000..2cd3826 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_queue_set.hpp @@ -0,0 +1,66 @@ +// +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_QUEUE_SET_HPP +#define ASIO_DETAIL_TIMER_QUEUE_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_queue_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class timer_queue_set +{ +public: + // Constructor. + ASIO_DECL timer_queue_set(); + + // Add a timer queue to the set. + ASIO_DECL void insert(timer_queue_base* q); + + // Remove a timer queue from the set. + ASIO_DECL void erase(timer_queue_base* q); + + // Determine whether all queues are empty. + ASIO_DECL bool all_empty() const; + + // Get the wait duration in milliseconds. + ASIO_DECL long wait_duration_msec(long max_duration) const; + + // Get the wait duration in microseconds. + ASIO_DECL long wait_duration_usec(long max_duration) const; + + // Dequeue all ready timers. + ASIO_DECL void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + ASIO_DECL void get_all_timers(op_queue& ops); + +private: + timer_queue_base* first_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/timer_queue_set.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_scheduler.hpp b/extern/asio-1.18.2/include/asio/detail/timer_scheduler.hpp new file mode 100644 index 0000000..8d9b4ed --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_scheduler.hpp @@ -0,0 +1,35 @@ +// +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_scheduler_fwd.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/winrt_timer_scheduler.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#elif defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor.hpp" +#else +# include "asio/detail/select_reactor.hpp" +#endif + +#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/timer_scheduler_fwd.hpp b/extern/asio-1.18.2/include/asio/detail/timer_scheduler_fwd.hpp new file mode 100644 index 0000000..15b5fbd --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/timer_scheduler_fwd.hpp @@ -0,0 +1,40 @@ +// +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP +#define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS_RUNTIME) +typedef class winrt_timer_scheduler timer_scheduler; +#elif defined(ASIO_HAS_IOCP) +typedef class win_iocp_io_context timer_scheduler; +#elif defined(ASIO_HAS_EPOLL) +typedef class epoll_reactor timer_scheduler; +#elif defined(ASIO_HAS_KQUEUE) +typedef class kqueue_reactor timer_scheduler; +#elif defined(ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor timer_scheduler; +#else +typedef class select_reactor timer_scheduler; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/tss_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/tss_ptr.hpp new file mode 100644 index 0000000..25e4d3d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/tss_ptr.hpp @@ -0,0 +1,69 @@ +// +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TSS_PTR_HPP +#define ASIO_DETAIL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_tss_ptr.hpp" +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# include "asio/detail/keyword_tss_ptr.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_tss_ptr.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_tss_ptr.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class tss_ptr +#if !defined(ASIO_HAS_THREADS) + : public null_tss_ptr +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + : public keyword_tss_ptr +#elif defined(ASIO_WINDOWS) + : public win_tss_ptr +#elif defined(ASIO_HAS_PTHREADS) + : public posix_tss_ptr +#endif +{ +public: + void operator=(T* value) + { +#if !defined(ASIO_HAS_THREADS) + null_tss_ptr::operator=(value); +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + keyword_tss_ptr::operator=(value); +#elif defined(ASIO_WINDOWS) + win_tss_ptr::operator=(value); +#elif defined(ASIO_HAS_PTHREADS) + posix_tss_ptr::operator=(value); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TSS_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/type_traits.hpp b/extern/asio-1.18.2/include/asio/detail/type_traits.hpp new file mode 100644 index 0000000..968f19a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/type_traits.hpp @@ -0,0 +1,156 @@ +// +// detail/type_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_TYPE_TRAITS_HPP +#define ASIO_DETAIL_TYPE_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_TYPE_TRAITS) +# include +#else // defined(ASIO_HAS_STD_TYPE_TRAITS) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) + +namespace asio { + +#if defined(ASIO_HAS_STD_TYPE_TRAITS) +using std::add_const; +using std::add_lvalue_reference; +using std::aligned_storage; +using std::alignment_of; +using std::conditional; +using std::decay; +using std::declval; +using std::enable_if; +using std::false_type; +using std::integral_constant; +using std::is_base_of; +using std::is_class; +using std::is_const; +using std::is_constructible; +using std::is_convertible; +using std::is_copy_constructible; +using std::is_destructible; +using std::is_function; +using std::is_move_constructible; +using std::is_nothrow_copy_constructible; +using std::is_nothrow_destructible; +using std::is_object; +using std::is_reference; +using std::is_same; +using std::is_scalar; +using std::remove_cv; +template +struct remove_cvref : remove_cv::type> {}; +using std::remove_pointer; +using std::remove_reference; +#if defined(ASIO_HAS_STD_INVOKE_RESULT) +template struct result_of; +template +struct result_of : std::invoke_result {}; +#else // defined(ASIO_HAS_STD_INVOKE_RESULT) +using std::result_of; +#endif // defined(ASIO_HAS_STD_INVOKE_RESULT) +using std::true_type; +#else // defined(ASIO_HAS_STD_TYPE_TRAITS) +using boost::add_const; +using boost::add_lvalue_reference; +using boost::aligned_storage; +using boost::alignment_of; +template +struct enable_if : boost::enable_if_c {}; +using boost::conditional; +using boost::decay; +using boost::declval; +using boost::false_type; +using boost::integral_constant; +using boost::is_base_of; +using boost::is_class; +using boost::is_const; +using boost::is_constructible; +using boost::is_convertible; +using boost::is_copy_constructible; +using boost::is_destructible; +using boost::is_function; +#if defined(ASIO_HAS_MOVE) +template +struct is_move_constructible : false_type {}; +#else // defined(ASIO_HAS_MOVE) +template +struct is_move_constructible : is_copy_constructible {}; +#endif // defined(ASIO_HAS_MOVE) +template +struct is_nothrow_copy_constructible : boost::has_nothrow_copy {}; +template +struct is_nothrow_destructible : boost::has_nothrow_destructor {}; +using boost::is_object; +using boost::is_reference; +using boost::is_same; +using boost::is_scalar; +using boost::remove_cv; +template +struct remove_cvref : remove_cv::type> {}; +using boost::remove_pointer; +using boost::remove_reference; +using boost::result_of; +using boost::true_type; +#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) + +template struct void_type { typedef void type; }; + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template struct conjunction : true_type {}; +template struct conjunction : T {}; +template struct conjunction : + conditional, Head>::type {}; + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +struct defaulted_constraint +{ + ASIO_CONSTEXPR defaulted_constraint() {} +}; + +template +struct constraint : enable_if {}; + +} // namespace asio + +#endif // ASIO_DETAIL_TYPE_TRAITS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/variadic_templates.hpp b/extern/asio-1.18.2/include/asio/detail/variadic_templates.hpp new file mode 100644 index 0000000..3bcc8d2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/variadic_templates.hpp @@ -0,0 +1,294 @@ +// +// detail/variadic_templates.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_VARIADIC_TEMPLATES_HPP +#define ASIO_DETAIL_VARIADIC_TEMPLATES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n + +# define ASIO_VARIADIC_TPARAMS_1 \ + typename T1 +# define ASIO_VARIADIC_TPARAMS_2 \ + typename T1, typename T2 +# define ASIO_VARIADIC_TPARAMS_3 \ + typename T1, typename T2, typename T3 +# define ASIO_VARIADIC_TPARAMS_4 \ + typename T1, typename T2, typename T3, typename T4 +# define ASIO_VARIADIC_TPARAMS_5 \ + typename T1, typename T2, typename T3, typename T4, typename T5 +# define ASIO_VARIADIC_TPARAMS_6 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6 +# define ASIO_VARIADIC_TPARAMS_7 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6, typename T7 +# define ASIO_VARIADIC_TPARAMS_8 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6, typename T7, typename T8 + +# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n + +# define ASIO_VARIADIC_TARGS_1 T1 +# define ASIO_VARIADIC_TARGS_2 T1, T2 +# define ASIO_VARIADIC_TARGS_3 T1, T2, T3 +# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 +# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 +# define ASIO_VARIADIC_TARGS_6 T1, T2, T3, T4, T5, T6 +# define ASIO_VARIADIC_TARGS_7 T1, T2, T3, T4, T5, T6, T7 +# define ASIO_VARIADIC_TARGS_8 T1, T2, T3, T4, T5, T6, T7, T8 + +# define ASIO_VARIADIC_BYVAL_PARAMS(n) \ + ASIO_VARIADIC_BYVAL_PARAMS_##n + +# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1 +# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2 +# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 +# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 +# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 +# define ASIO_VARIADIC_BYVAL_PARAMS_6 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6 +# define ASIO_VARIADIC_BYVAL_PARAMS_7 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6, T7 x7 +# define ASIO_VARIADIC_BYVAL_PARAMS_8 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6, T7 x7, T8 x8 + +# define ASIO_VARIADIC_BYVAL_ARGS(n) \ + ASIO_VARIADIC_BYVAL_ARGS_##n + +# define ASIO_VARIADIC_BYVAL_ARGS_1 x1 +# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2 +# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 +# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 +# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 +# define ASIO_VARIADIC_BYVAL_ARGS_6 x1, x2, x3, x4, x5, x6 +# define ASIO_VARIADIC_BYVAL_ARGS_7 x1, x2, x3, x4, x5, x6, x7 +# define ASIO_VARIADIC_BYVAL_ARGS_8 x1, x2, x3, x4, x5, x6, x7, x8 + +# define ASIO_VARIADIC_CONSTREF_PARAMS(n) \ + ASIO_VARIADIC_CONSTREF_PARAMS_##n + +# define ASIO_VARIADIC_CONSTREF_PARAMS_1 \ + const T1& x1 +# define ASIO_VARIADIC_CONSTREF_PARAMS_2 \ + const T1& x1, const T2& x2 +# define ASIO_VARIADIC_CONSTREF_PARAMS_3 \ + const T1& x1, const T2& x2, const T3& x3 +# define ASIO_VARIADIC_CONSTREF_PARAMS_4 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4 +# define ASIO_VARIADIC_CONSTREF_PARAMS_5 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5 +# define ASIO_VARIADIC_CONSTREF_PARAMS_6 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6 +# define ASIO_VARIADIC_CONSTREF_PARAMS_7 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6, const T7& x7 +# define ASIO_VARIADIC_CONSTREF_PARAMS_8 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6, const T7& x7, const T8& x8 + +# define ASIO_VARIADIC_MOVE_PARAMS(n) \ + ASIO_VARIADIC_MOVE_PARAMS_##n + +# define ASIO_VARIADIC_MOVE_PARAMS_1 \ + ASIO_MOVE_ARG(T1) x1 +# define ASIO_VARIADIC_MOVE_PARAMS_2 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2 +# define ASIO_VARIADIC_MOVE_PARAMS_3 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3 +# define ASIO_VARIADIC_MOVE_PARAMS_4 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4 +# define ASIO_VARIADIC_MOVE_PARAMS_5 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ + ASIO_MOVE_ARG(T5) x5 +# define ASIO_VARIADIC_MOVE_PARAMS_6 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ + ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6 +# define ASIO_VARIADIC_MOVE_PARAMS_7 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ + ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \ + ASIO_MOVE_ARG(T7) x7 +# define ASIO_VARIADIC_MOVE_PARAMS_8 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ + ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \ + ASIO_MOVE_ARG(T7) x7, ASIO_MOVE_ARG(T8) x8 + +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \ + ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n + +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_1 \ + ASIO_MOVE_ARG(T1) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_2 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_3 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_4 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_5 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \ + ASIO_MOVE_ARG(T5) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_6 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \ + ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_7 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \ + ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \ + ASIO_MOVE_ARG(T7) +# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_8 \ + ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \ + ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \ + ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \ + ASIO_MOVE_ARG(T7), ASIO_MOVE_ARG(T8) + +# define ASIO_VARIADIC_MOVE_ARGS(n) \ + ASIO_VARIADIC_MOVE_ARGS_##n + +# define ASIO_VARIADIC_MOVE_ARGS_1 \ + ASIO_MOVE_CAST(T1)(x1) +# define ASIO_VARIADIC_MOVE_ARGS_2 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2) +# define ASIO_VARIADIC_MOVE_ARGS_3 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3) +# define ASIO_VARIADIC_MOVE_ARGS_4 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4) +# define ASIO_VARIADIC_MOVE_ARGS_5 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ + ASIO_MOVE_CAST(T5)(x5) +# define ASIO_VARIADIC_MOVE_ARGS_6 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ + ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6) +# define ASIO_VARIADIC_MOVE_ARGS_7 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ + ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \ + ASIO_MOVE_CAST(T7)(x7) +# define ASIO_VARIADIC_MOVE_ARGS_8 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ + ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \ + ASIO_MOVE_CAST(T7)(x7), ASIO_MOVE_CAST(T8)(x8) + +# define ASIO_VARIADIC_DECLVAL(n) \ + ASIO_VARIADIC_DECLVAL_##n + +# define ASIO_VARIADIC_DECLVAL_1 \ + declval() +# define ASIO_VARIADIC_DECLVAL_2 \ + declval(), declval() +# define ASIO_VARIADIC_DECLVAL_3 \ + declval(), declval(), declval() +# define ASIO_VARIADIC_DECLVAL_4 \ + declval(), declval(), declval(), declval() +# define ASIO_VARIADIC_DECLVAL_5 \ + declval(), declval(), declval(), declval(), \ + declval() +# define ASIO_VARIADIC_DECLVAL_6 \ + declval(), declval(), declval(), declval(), \ + declval(), declval() +# define ASIO_VARIADIC_DECLVAL_7 \ + declval(), declval(), declval(), declval(), \ + declval(), declval(), declval() +# define ASIO_VARIADIC_DECLVAL_8 \ + declval(), declval(), declval(), declval(), \ + declval(), declval(), declval(), declval() + +# define ASIO_VARIADIC_MOVE_DECLVAL(n) \ + ASIO_VARIADIC_MOVE_DECLVAL_##n + +# define ASIO_VARIADIC_MOVE_DECLVAL_1 \ + declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_2 \ + declval(), declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_3 \ + declval(), declval(), \ + declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_4 \ + declval(), declval(), \ + declval(), declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_5 \ + declval(), declval(), \ + declval(), declval(), \ + declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_6 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_7 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval(), \ + declval() +# define ASIO_VARIADIC_MOVE_DECLVAL_8 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval() + +# define ASIO_VARIADIC_DECAY(n) \ + ASIO_VARIADIC_DECAY_##n + +# define ASIO_VARIADIC_DECAY_1 \ + typename decay::type +# define ASIO_VARIADIC_DECAY_2 \ + typename decay::type, typename decay::type +# define ASIO_VARIADIC_DECAY_3 \ + typename decay::type, typename decay::type, \ + typename decay::type +# define ASIO_VARIADIC_DECAY_4 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type +# define ASIO_VARIADIC_DECAY_5 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type +# define ASIO_VARIADIC_DECAY_6 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type +# define ASIO_VARIADIC_DECAY_7 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type +# define ASIO_VARIADIC_DECAY_8 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type + +# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) +# define ASIO_VARIADIC_GENERATE_5(m) m(1) m(2) m(3) m(4) m(5) + +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/wait_handler.hpp b/extern/asio-1.18.2/include/asio/detail/wait_handler.hpp new file mode 100644 index 0000000..6a87a53 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/wait_handler.hpp @@ -0,0 +1,90 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WAIT_HANDLER_HPP +#define ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/wait_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class wait_handler : public wait_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler& h, const IoExecutor& io_ex) + : wait_op(&wait_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + + ASIO_HANDLER_COMPLETION((*h)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + h->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(h->handler_, h->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/wait_op.hpp b/extern/asio-1.18.2/include/asio/detail/wait_op.hpp new file mode 100644 index 0000000..a13286a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/wait_op.hpp @@ -0,0 +1,45 @@ +// +// detail/wait_op.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WAIT_OP_HPP +#define ASIO_DETAIL_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class wait_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + wait_op(func_type func) + : operation(func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WAIT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_event.hpp b/extern/asio-1.18.2/include/asio/detail/win_event.hpp new file mode 100644 index 0000000..3f00e00 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_event.hpp @@ -0,0 +1,164 @@ +// +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_EVENT_HPP +#define ASIO_DETAIL_WIN_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_event + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL win_event(); + + // Destructor. + ASIO_DECL ~win_event(); + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::SetEvent(events_[0]); + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::SetEvent(events_[1]); + } + + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::SetEvent(events_[1]); + lock.unlock(); + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::SetEvent(events_[1]); + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + ::ResetEvent(events_[0]); + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); +#if defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, INFINITE); +#endif // defined(ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); + DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0; +#if defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, msec, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, msec); +#endif // defined(ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + HANDLE events_[2]; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_EVENT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_fd_set_adapter.hpp b/extern/asio-1.18.2/include/asio/detail/win_fd_set_adapter.hpp new file mode 100644 index 0000000..f5e19f0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_fd_set_adapter.hpp @@ -0,0 +1,149 @@ +// +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class win_fd_set_adapter : noncopyable +{ +public: + enum { default_fd_set_size = 1024 }; + + win_fd_set_adapter() + : capacity_(default_fd_set_size), + max_descriptor_(invalid_socket) + { + fd_set_ = static_cast(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (capacity_))); + fd_set_->fd_count = 0; + } + + ~win_fd_set_adapter() + { + ::operator delete(fd_set_); + } + + void reset() + { + fd_set_->fd_count = 0; + max_descriptor_ = invalid_socket; + } + + bool set(socket_type descriptor) + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + if (fd_set_->fd_array[i] == descriptor) + return true; + + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = descriptor; + return true; + } + + void set(reactor_op_queue& operations, op_queue&) + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first; + } + } + + bool is_set(socket_type descriptor) const + { + return !!__WSAFDIsSet(descriptor, + const_cast(reinterpret_cast(fd_set_))); + } + + operator fd_set*() + { + return reinterpret_cast(fd_set_); + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue& operations, + op_queue& ops) const + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + operations.perform_operations(fd_set_->fd_array[i], ops); + } + +private: + // This structure is defined to be compatible with the Windows API fd_set + // structure, but without being dependent on the value of FD_SETSIZE. We use + // the "struct hack" to allow the number of descriptors to be varied at + // runtime. + struct win_fd_set + { + u_int fd_count; + SOCKET fd_array[1]; + }; + + // Increase the fd_set_ capacity to at least the specified number of elements. + void reserve(u_int n) + { + if (n <= capacity_) + return; + + u_int new_capacity = capacity_ + capacity_ / 2; + if (new_capacity < n) + new_capacity = n; + + win_fd_set* new_fd_set = static_cast(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (new_capacity))); + + new_fd_set->fd_count = fd_set_->fd_count; + for (u_int i = 0; i < fd_set_->fd_count; ++i) + new_fd_set->fd_array[i] = fd_set_->fd_array[i]; + + ::operator delete(fd_set_); + fd_set_ = new_fd_set; + capacity_ = new_capacity; + } + + win_fd_set* fd_set_; + u_int capacity_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_fenced_block.hpp b/extern/asio-1.18.2/include/asio/detail/win_fenced_block.hpp new file mode 100644 index 0000000..77d1eb1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_fenced_block.hpp @@ -0,0 +1,90 @@ +// +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_FENCED_BLOCK_HPP +#define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && !defined(UNDER_CE) + +#include "asio/detail/socket_types.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit win_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit win_fenced_block(full_t) + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(ASIO_MSVC) \ + && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else + MemoryBarrier(); +#endif + } + + // Destructor. + ~win_fenced_block() + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(ASIO_MSVC) \ + && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else + MemoryBarrier(); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_global.hpp b/extern/asio-1.18.2/include/asio/detail/win_global.hpp new file mode 100644 index 0000000..f77976e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_global.hpp @@ -0,0 +1,71 @@ +// +// detail/win_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_GLOBAL_HPP +#define ASIO_DETAIL_WIN_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/static_mutex.hpp" +#include "asio/detail/tss_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct win_global_impl +{ + // Destructor automatically cleans up the global. + ~win_global_impl() + { + delete ptr_; + } + + static win_global_impl instance_; + static static_mutex mutex_; + T* ptr_; + static tss_ptr tss_ptr_; +}; + +template +win_global_impl win_global_impl::instance_ = { 0 }; + +template +static_mutex win_global_impl::mutex_ = ASIO_STATIC_MUTEX_INIT; + +template +tss_ptr win_global_impl::tss_ptr_; + +template +T& win_global() +{ + if (static_cast(win_global_impl::tss_ptr_) == 0) + { + win_global_impl::mutex_.init(); + static_mutex::scoped_lock lock(win_global_impl::mutex_); + if (win_global_impl::instance_.ptr_ == 0) + win_global_impl::instance_.ptr_ = new T; + win_global_impl::tss_ptr_ = win_global_impl::instance_.ptr_; + } + + return *win_global_impl::tss_ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_GLOBAL_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_read_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 0000000..f11abb1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,117 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_handle_read_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op(const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = asio::error::eof; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_service.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_service.hpp new file mode 100644 index 0000000..a9bee45 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_service.hpp @@ -0,0 +1,335 @@ +// +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/win_iocp_handle_read_op.hpp" +#include "asio/detail/win_iocp_handle_write_op.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_handle_service : + public execution_context_service_base +{ +public: + // The native type of a stream handle. + typedef HANDLE native_handle_type; + + // The implementation type of the stream handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + safe_cancellation_thread_id_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_iocp_handle_service; + + // The native stream handle representation. + native_handle_type handle_; + + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the handle. + DWORD safe_cancellation_thread_id_; + + // Pointers to adjacent handle implementations in linked list. + implementation_type* next_; + implementation_type* prev_; + }; + + ASIO_DECL win_iocp_handle_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + ASIO_DECL void move_assign(implementation_type& impl, + win_iocp_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE; + } + + // Destroy a handle implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Write the given data. Returns the number of bytes written. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return write_some_at(impl, 0, buffers, ec); + } + + // Write the given data at the specified offset. Returns the number of bytes + // written. + template + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + asio::const_buffer buffer = + buffer_sequence_adapter::first(buffers); + + return do_write(impl, offset, buffer, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_write_some")); + + start_write_op(impl, 0, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous write at a specified offset. The data being written + // must be valid for the lifetime of the asynchronous operation. + template + void async_write_some_at(implementation_type& impl, + uint64_t offset, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_write_some_at")); + + start_write_op(impl, offset, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return read_some_at(impl, 0, buffers, ec); + } + + // Read some data at a specified offset. Returns the number of bytes received. + template + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + asio::mutable_buffer buffer = + buffer_sequence_adapter::first(buffers); + + return do_read(impl, offset, buffer, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_read_some")); + + start_read_op(impl, 0, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous read at a specified offset. The buffer for the data + // being received must be valid for the lifetime of the asynchronous + // operation. + template + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_read_some_at")); + + start_read_op(impl, offset, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + +private: + // Prevent the use of the null_buffers type with this service. + size_t write_some(implementation_type& impl, + const null_buffers& buffers, asio::error_code& ec); + size_t write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, asio::error_code& ec); + template + void async_write_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template + void async_write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); + size_t read_some(implementation_type& impl, + const null_buffers& buffers, asio::error_code& ec); + size_t read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, asio::error_code& ec); + template + void async_read_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template + void async_read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); + + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; + + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_write(implementation_type& impl, + uint64_t offset, const asio::const_buffer& buffer, + asio::error_code& ec); + + // Helper function to start a write operation. + ASIO_DECL void start_write_op(implementation_type& impl, + uint64_t offset, const asio::const_buffer& buffer, + operation* op); + + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_read(implementation_type& impl, + uint64_t offset, const asio::mutable_buffer& buffer, + asio::error_code& ec); + + // Helper function to start a read operation. + ASIO_DECL void start_read_op(implementation_type& impl, + uint64_t offset, const asio::mutable_buffer& buffer, + operation* op); + + // Update the ID of the thread from which cancellation is safe. + ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); + + // Helper function to close a handle when the associated object is being + // destroyed. + ASIO_DECL void close_for_destruction(implementation_type& impl); + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // Mutex to protect access to the linked list of implementations. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_handle_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_write_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 0000000..a686205 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,110 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_handle_write_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_io_context.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_io_context.hpp new file mode 100644 index 0000000..9cc1b2e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_io_context.hpp @@ -0,0 +1,339 @@ +// +// detail/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP +#define ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/win_iocp_thread_info.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class wait_op; + +class win_iocp_io_context + : public execution_context_service_base, + public thread_context +{ +public: + // Constructor. Specifies a concurrency hint that is passed through to the + // underlying I/O completion port. + ASIO_DECL win_iocp_io_context(asio::execution_context& ctx, + int concurrency_hint = -1, bool own_thread = true); + + // Destructor. + ASIO_DECL ~win_iocp_io_context(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Initialise the task. Nothing to do here. + void init_task() + { + } + + // Register a handle with the IO completion port. + ASIO_DECL asio::error_code register_handle( + HANDLE handle, asio::error_code& ec); + + // Run the event loop until stopped or no more work. + ASIO_DECL size_t run(asio::error_code& ec); + + // Run until stopped or one operation is performed. + ASIO_DECL size_t run_one(asio::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + ASIO_DECL size_t wait_one(long usec, asio::error_code& ec); + + // Poll for operations without blocking. + ASIO_DECL size_t poll(asio::error_code& ec); + + // Poll for one operation without blocking. + ASIO_DECL size_t poll_one(asio::error_code& ec); + + // Stop the event processing loop. + ASIO_DECL void stop(); + + // Determine whether the io_context is stopped. + bool stopped() const + { + return ::InterlockedExchangeAdd(&stopped_, 0) != 0; + } + + // Restart in preparation for a subsequent run invocation. + void restart() + { + ::InterlockedExchange(&stopped_, 0); + } + + // Notify that some work has started. + void work_started() + { + ::InterlockedIncrement(&outstanding_work_); + } + + // Notify that some work has finished. + void work_finished() + { + if (::InterlockedDecrement(&outstanding_work_) == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + ASIO_DECL bool can_dispatch(); + + /// Capture the current exception so it can be rethrown from a run function. + ASIO_DECL void capture_current_exception(); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + void post_immediate_completion(win_iocp_operation* op, bool) + { + work_started(); + post_deferred_completion(op); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + ASIO_DECL void post_deferred_completion(win_iocp_operation* op); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operations. + ASIO_DECL void post_deferred_completions( + op_queue& ops); + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() has not yet been + // called for the operation. + void post_private_immediate_completion(win_iocp_operation* op) + { + post_immediate_completion(op, false); + } + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() was previously called + // for the operation. + void post_private_deferred_completion(win_iocp_operation* op) + { + post_deferred_completion(op); + } + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + void do_dispatch(operation* op) + { + post_immediate_completion(op, false); + } + + // Process unfinished operations as part of a shutdown operation. Assumes + // that work_started() was previously called for the operations. + ASIO_DECL void abandon_operations(op_queue& ops); + + // Called after starting an overlapped I/O operation that did not complete + // immediately. The caller must have already called work_started() prior to + // starting the operation. + ASIO_DECL void on_pending(win_iocp_operation* op); + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + ASIO_DECL void on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred = 0); + + // Add a new timer queue to the service. + template + void add_timer_queue(timer_queue& timer_queue); + + // Remove a timer queue from the service. + template + void remove_timer_queue(timer_queue& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from); + + // Get the concurrency hint that was used to initialise the io_context. + int concurrency_hint() const + { + return concurrency_hint_; + } + +private: +#if defined(WINVER) && (WINVER < 0x0500) + typedef DWORD dword_ptr_t; + typedef ULONG ulong_ptr_t; +#else // defined(WINVER) && (WINVER < 0x0500) + typedef DWORD_PTR dword_ptr_t; + typedef ULONG_PTR ulong_ptr_t; +#endif // defined(WINVER) && (WINVER < 0x0500) + + // Dequeues at most one operation from the I/O completion port, and then + // executes it. Returns the number of operations that were dequeued (i.e. + // either 0 or 1). + ASIO_DECL size_t do_one(DWORD msec, + win_iocp_thread_info& this_thread, asio::error_code& ec); + + // Helper to calculate the GetQueuedCompletionStatus timeout. + ASIO_DECL static DWORD get_gqcs_timeout(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); + + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit; + + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } + }; + + // The IO completion port used for queueing operations. + auto_handle iocp_; + + // The count of unfinished work. + long outstanding_work_; + + // Flag to indicate whether the event loop has been stopped. + mutable long stopped_; + + // Flag to indicate whether there is an in-flight stop event. Every event + // posted using PostQueuedCompletionStatus consumes non-paged pool, so to + // avoid exhausting this resouce we limit the number of outstanding events. + long stop_event_posted_; + + // Flag to indicate whether the service has been shut down. + long shutdown_; + + enum + { + // Timeout to use with GetQueuedCompletionStatus on older versions of + // Windows. Some versions of windows have a "bug" where a call to + // GetQueuedCompletionStatus can appear stuck even though there are events + // waiting on the queue. Using a timeout helps to work around the issue. + default_gqcs_timeout = 500, + + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, + + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, + + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, + + // Completion key value to indicate that an operation has posted with the + // original last_error and bytes_transferred values stored in the fields of + // the OVERLAPPED structure. + overlapped_contains_result = 2 + }; + + // Timeout to use with GetQueuedCompletionStatus. + const DWORD gqcs_timeout_; + + // Helper class to run the scheduler in its own thread. + struct thread_function; + friend struct thread_function; + + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; + + // Background thread used for processing timeouts. + scoped_ptr timer_thread_; + + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; + + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; + + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The operations that are ready to dispatch. + op_queue completed_ops_; + + // The concurrency hint used to initialise the io_context. + const int concurrency_hint_; + + // The thread that is running the io_context. + scoped_ptr thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/win_iocp_io_context.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_io_context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_null_buffers_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 0000000..5aedd7a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,127 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(asio::error_code(), + &win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_operation.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_operation.hpp new file mode 100644 index 0000000..1349192 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_operation.hpp @@ -0,0 +1,96 @@ +// +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_OPERATION_HPP +#define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/handler_tracking.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_io_context; + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class win_iocp_operation + : public OVERLAPPED + ASIO_ALSO_INHERIT_TRACKED_HANDLER +{ +public: + typedef win_iocp_operation operation_type; + + void complete(void* owner, const asio::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, asio::error_code(), 0); + } + +protected: + typedef void (*func_type)( + void*, win_iocp_operation*, + const asio::error_code&, std::size_t); + + win_iocp_operation(func_type func) + : next_(0), + func_(func) + { + reset(); + } + + // Prevents deletion through this type. + ~win_iocp_operation() + { + } + + void reset() + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + hEvent = 0; + ready_ = 0; + } + +private: + friend class op_queue_access; + friend class win_iocp_io_context; + win_iocp_operation* next_; + func_type func_; + long ready_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 0000000..247375b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,96 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_overlapped_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_ptr.hpp new file mode 100644 index 0000000..5249abb --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_overlapped_ptr.hpp @@ -0,0 +1,171 @@ +// +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP +#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/io_context.hpp" +#include "asio/query.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/win_iocp_overlapped_op.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. +class win_iocp_overlapped_ptr + : private noncopyable +{ +public: + // Construct an empty win_iocp_overlapped_ptr. + win_iocp_overlapped_ptr() + : ptr_(0), + iocp_service_(0) + { + } + + // Construct an win_iocp_overlapped_ptr to contain the specified handler. + template + explicit win_iocp_overlapped_ptr(const Executor& ex, + ASIO_MOVE_ARG(Handler) handler) + : ptr_(0), + iocp_service_(0) + { + this->reset(ex, ASIO_MOVE_CAST(Handler)(handler)); + } + + // Destructor automatically frees the OVERLAPPED object unless released. + ~win_iocp_overlapped_ptr() + { + reset(); + } + + // Reset to empty. + void reset() + { + if (ptr_) + { + ptr_->destroy(); + ptr_ = 0; + iocp_service_->work_finished(); + iocp_service_ = 0; + } + } + + // Reset to contain the specified handler, freeing any current OVERLAPPED + // object. + template + void reset(const Executor& ex, Handler handler) + { + win_iocp_io_context* iocp_service = this->get_iocp_service(ex); + + typedef win_iocp_overlapped_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, ex); + + ASIO_HANDLER_CREATION((ex.context(), *p.p, + "iocp_service", iocp_service, 0, "overlapped")); + + iocp_service->work_started(); + reset(); + ptr_ = p.p; + p.v = p.p = 0; + iocp_service_ = iocp_service; + } + + // Get the contained OVERLAPPED object. + OVERLAPPED* get() + { + return ptr_; + } + + // Get the contained OVERLAPPED object. + const OVERLAPPED* get() const + { + return ptr_; + } + + // Release ownership of the OVERLAPPED object. + OVERLAPPED* release() + { + if (ptr_) + iocp_service_->on_pending(ptr_); + + OVERLAPPED* tmp = ptr_; + ptr_ = 0; + iocp_service_ = 0; + return tmp; + } + + // Post completion notification for overlapped operation. Releases ownership. + void complete(const asio::error_code& ec, + std::size_t bytes_transferred) + { + if (ptr_) + { + iocp_service_->on_completion(ptr_, ec, + static_cast(bytes_transferred)); + ptr_ = 0; + iocp_service_ = 0; + } + } + +private: + template + static win_iocp_io_context* get_iocp_service(const Executor& ex, + typename enable_if< + can_query::value + >::type* = 0) + { + return &use_service( + asio::query(ex, execution::context)); + } + + template + static win_iocp_io_context* get_iocp_service(const Executor& ex, + typename enable_if< + !can_query::value + >::type* = 0) + { + return &use_service(ex.context()); + } + + static win_iocp_io_context* get_iocp_service( + const io_context::executor_type& ex) + { + return &asio::query(ex, execution::context).impl_; + } + + win_iocp_operation* ptr_; + win_iocp_io_context* iocp_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_serial_port_service.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_serial_port_service.hpp new file mode 100644 index 0000000..d1d9d82 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_serial_port_service.hpp @@ -0,0 +1,232 @@ +// +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#include +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/win_iocp_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend win_iocp_handle_service to provide serial port support. +class win_iocp_serial_port_service : + public execution_context_service_base +{ +public: + // The native type of a serial port. + typedef win_iocp_handle_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef win_iocp_handle_service::implementation_type implementation_type; + + // Constructor. + ASIO_DECL win_iocp_serial_port_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + handle_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + handle_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + win_iocp_serial_port_service& other_service, + implementation_type& other_impl) + { + handle_service_.move_assign(impl, + other_service.handle_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + handle_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); + + // Assign a native handle to a serial port implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) + { + return handle_service_.assign(impl, handle, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return handle_service_.is_open(impl); + } + + // Destroy a serial port implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return handle_service_.native_handle(impl); + } + + // Cancel all operations associated with the handle. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template + asio::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, asio::error_code& ec) + { + return do_set_option(impl, + &win_iocp_serial_port_service::store_option, + &option, ec); + } + + // Get an option from the serial port. + template + asio::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, asio::error_code& ec) const + { + return do_get_option(impl, + &win_iocp_serial_port_service::load_option, + &option, ec); + } + + // Send a break sequence to the serial port. + asio::error_code send_break(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_write_some(impl, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_read_some(impl, buffers, handler, io_ex); + } + +private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, ::DCB&, asio::error_code&); + + // Helper function template to store a serial port option. + template + static asio::error_code store_option(const void* option, + ::DCB& storage, asio::error_code& ec) + { + static_cast(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const ::DCB&, asio::error_code&); + + // Helper function template to load a serial port option. + template + static asio::error_code load_option(void* option, + const ::DCB& storage, asio::error_code& ec) + { + static_cast(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_accept_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 0000000..1f21685 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,312 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_accept_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; + handler_work work_; +}; + +#if defined(ASIO_HAS_MOVE) + +template +class win_iocp_socket_move_accept_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); + + win_iocp_socket_move_accept_op( + win_iocp_socket_service_base& socket_service, socket_type socket, + const Protocol& protocol, const PeerIoExecutor& peer_io_ex, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_move_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer_io_ex), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_move_accept_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Protocol::socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2 + handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec, + ASIO_MOVE_CAST(peer_socket_type)(o->peer_)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + typedef typename Protocol::socket::template + rebind_executor::other peer_socket_type; + + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + peer_socket_type peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; + handler_work work_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_connect_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_connect_op.hpp new file mode 100644 index 0000000..f7be04d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_connect_op.hpp @@ -0,0 +1,135 @@ +// +// detail/win_iocp_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_socket_connect_op_base : public reactor_op +{ +public: + win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(asio::error_code(), + &win_iocp_socket_connect_op_base::do_perform, complete_func), + socket_(socket), + connect_ex_(false) + { + } + + static status do_perform(reactor_op* base) + { + win_iocp_socket_connect_op_base* o( + static_cast(base)); + + return socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + } + + socket_type socket_; + bool connect_ex_; +}; + +template +class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op); + + win_iocp_socket_connect_op(socket_type socket, + Handler& handler, const IoExecutor& io_ex) + : win_iocp_socket_connect_op_base(socket, + &win_iocp_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_connect_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner) + { + if (o->connect_ex_) + socket_ops::complete_iocp_connect(o->socket_, ec); + else + ec = o->ec_; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recv_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 0000000..0da2982 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,124 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_recv_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter::all_empty(o->buffers_), + ec, bytes_transferred); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvfrom_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 0000000..40c9114 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,133 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvfrom_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvmsg_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvmsg_op.hpp new file mode 100644 index 0000000..a14a4b5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -0,0 +1,125 @@ +// +// detail/win_iocp_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvmsg_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op); + + win_iocp_socket_recvmsg_op( + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_recvmsg_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + out_flags_(out_flags), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvmsg_op* o( + static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec); + o->out_flags_ = 0; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + socket_base::message_flags& out_flags_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_send_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 0000000..3a40abe --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,118 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_send_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service.hpp new file mode 100644 index 0000000..e2c42c2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service.hpp @@ -0,0 +1,581 @@ +// +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/win_iocp_io_context.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_accept_op.hpp" +#include "asio/detail/win_iocp_socket_connect_op.hpp" +#include "asio/detail/win_iocp_socket_recvfrom_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_socket_service : + public execution_context_service_base >, + public win_iocp_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + class native_handle_type + { + public: + native_handle_type(socket_type s) + : socket_(s), + have_remote_endpoint_(false) + { + } + + native_handle_type(socket_type s, const endpoint_type& ep) + : socket_(s), + have_remote_endpoint_(true), + remote_endpoint_(ep) + { + } + + void operator=(socket_type s) + { + socket_ = s; + have_remote_endpoint_ = false; + remote_endpoint_ = endpoint_type(); + } + + operator socket_type() const + { + return socket_; + } + + bool have_remote_endpoint() const + { + return have_remote_endpoint_; + } + + endpoint_type remote_endpoint() const + { + return remote_endpoint_; + } + + private: + socket_type socket_; + bool have_remote_endpoint_; + endpoint_type remote_endpoint_; + }; + + // The implementation type of the socket. + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; + + // A cached remote endpoint. + endpoint_type remote_endpoint_; + }; + + // Constructor. + win_iocp_socket_service(execution_context& context) + : execution_context_service_base< + win_iocp_socket_service >(context), + win_iocp_socket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) ASIO_NOEXCEPT + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + win_iocp_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type& impl, + win_iocp_socket_service&, + typename win_iocp_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = typename Protocol1::endpoint(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); + } + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); + } + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + if (impl.have_remote_endpoint_) + return native_handle_type(impl.socket_, impl.remote_endpoint_); + return native_handle_type(impl.socket_); + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + buffer_sequence_adapter bufs(buffers); + + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast(destination.size()), + flags, p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endp, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvfrom_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, + buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_from_op(impl, bufs.buffers(), bufs.count(), + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Accept a new connection. + template + asio::error_code accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, asio::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_accept_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, peer.is_open(), p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } + +#if defined(ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_move_accept_op< + protocol_type, PeerIoExecutor, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_ex, peer_endpoint, enable_connection_aborted, + handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, false, p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } +#endif // defined(ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_connect_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), + peer_endpoint.data(), static_cast(peer_endpoint.size()), p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service_base.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 0000000..2a1f644 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,600 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/win_iocp_io_context.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_connect_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_recv_op.hpp" +#include "asio/detail/win_iocp_socket_recvmsg_op.hpp" +#include "asio/detail/win_iocp_wait_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + select_reactor::per_descriptor_data reactor_data_; + +#if defined(ASIO_ENABLE_CANCELIO) + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL win_iocp_socket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl) ASIO_NOEXCEPT; + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_wait_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + switch (w) + { + case socket_base::wait_read: + start_null_buffers_receive_op(impl, 0, p.p); + break; + case socket_base::wait_write: + start_reactor_op(impl, select_reactor::write_op, p.p); + break; + case socket_base::wait_error: + start_reactor_op(impl, select_reactor::except_op, p.p); + break; + default: + p.p->ec_ = asio::error::invalid_argument; + iocp_service_.post_immediate_completion(p.p, is_continuation); + break; + } + + p.v = p.p = 0; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send")); + + buffer_sequence_adapter bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, + buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, + buffers, out_flags, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Reset out_flags since it can be given no sensible value at this time. + out_flags = 0; + + start_null_buffers_receive_op(impl, in_flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, asio::error_code& ec); + + // Helper function to start an asynchronous send operation. + ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the reactor. + ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + int family, int type, const socket_addr_type* remote_addr, + std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op); + + // Helper function to close a socket when the associated object is being + // destroyed. + ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + ASIO_DECL void update_cancellation_thread_id( + base_implementation_type& impl); + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the execution context and a pointer to it is + // cached in this service. + ASIO_DECL select_reactor& get_reactor(); + + // The type of a ConnectEx function pointer, as old SDKs may not provide it. + typedef BOOL (PASCAL *connect_ex_fn)(SOCKET, + const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*); + + // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has + // been obtained yet, one is obtained using WSAIoctl and the pointer is + // cached. Returns a null pointer if ConnectEx is not available. + ASIO_DECL connect_ex_fn get_connect_ex( + base_implementation_type& impl, int type); + + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + ASIO_DECL nt_set_info_fn get_nt_set_info(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // The execution context used to obtain the reactor, if required. + execution_context& context_; + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + select_reactor* reactor_; + + // Pointer to ConnectEx implementation. + void* connect_ex_; + + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_thread_info.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_thread_info.hpp new file mode 100644 index 0000000..2b9b1bf --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_thread_info.hpp @@ -0,0 +1,34 @@ +// +// detail/win_iocp_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP +#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_thread_info : public thread_info_base +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_iocp_wait_op.hpp b/extern/asio-1.18.2/include/asio/detail/win_iocp_wait_op.hpp new file mode 100644 index 0000000..b17fe40 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_iocp_wait_op.hpp @@ -0,0 +1,128 @@ +// +// detail/win_iocp_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class win_iocp_wait_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op); + + win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(asio::error_code(), + &win_iocp_wait_op::do_perform, + &win_iocp_wait_op::do_complete), + cancel_token_(cancel_token), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_wait_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; + handler_work work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/win_mutex.hpp new file mode 100644 index 0000000..aed9ad9 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_mutex.hpp @@ -0,0 +1,78 @@ +// +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_MUTEX_HPP +#define ASIO_DETAIL_WIN_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock scoped_lock; + + // Constructor. + ASIO_DECL win_mutex(); + + // Destructor. + ~win_mutex() + { + ::DeleteCriticalSection(&crit_section_); + } + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + +private: + // Initialisation must be performed in a separate function to the constructor + // since the compiler does not support the use of structured exceptions and + // C++ exceptions in the same function. + ASIO_DECL int do_init(); + + ::CRITICAL_SECTION crit_section_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_object_handle_service.hpp b/extern/asio-1.18.2/include/asio/detail/win_object_handle_service.hpp new file mode 100644 index 0000000..a80c27d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_object_handle_service.hpp @@ -0,0 +1,195 @@ +// +// detail/win_object_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// 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 ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP +#define ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/wait_handler.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_object_handle_service : + public execution_context_service_base +{ +public: + // The native type of an object handle. + typedef HANDLE native_handle_type; + + // The implementation type of the object handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + wait_handle_(INVALID_HANDLE_VALUE), + owner_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_object_handle_service; + + // The native object handle representation. May be accessed or modified + // without locking the mutex. + native_handle_type handle_; + + // The handle used to unregister the wait operation. The mutex must be + // locked when accessing or modifying this member. + HANDLE wait_handle_; + + // The operations waiting on the object handle. If there is a registered + // wait then the mutex must be locked when accessing or modifying this + // member + op_queue op_queue_; + + // The service instance that owns the object handle implementation. + win_object_handle_service* owner_; + + // Pointers to adjacent handle implementations in linked list. The mutex + // must be locked when accessing or modifying these members. + implementation_type* next_; + implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL win_object_handle_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + ASIO_DECL void move_assign(implementation_type& impl, + win_object_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0; + } + + // Destroy a handle implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Perform a synchronous wait for the object to enter a signalled state. + ASIO_DECL void wait(implementation_type& impl, + asio::error_code& ec); + + /// Start an asynchronous wait. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to start an asynchronous wait operation. + ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op); + + // Helper function to register a wait operation. + ASIO_DECL void register_wait_callback( + implementation_type& impl, mutex::scoped_lock& lock); + + // Callback function invoked when the registered wait completes. + static ASIO_DECL VOID CALLBACK wait_callback( + PVOID param, BOOLEAN timeout); + + // The scheduler used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Mutex to protect access to internal state. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_object_handle_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_static_mutex.hpp b/extern/asio-1.18.2/include/asio/detail/win_static_mutex.hpp new file mode 100644 index 0000000..4538c3d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_static_mutex.hpp @@ -0,0 +1,74 @@ +// +// detail/win_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_STATIC_MUTEX_HPP +#define ASIO_DETAIL_WIN_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_static_mutex +{ + typedef asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + ASIO_DECL void init(); + + // Initialisation must be performed in a separate function to the "public" + // init() function since the compiler does not support the use of structured + // exceptions and C++ exceptions in the same function. + ASIO_DECL int do_init(); + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + + bool initialised_; + ::CRITICAL_SECTION crit_section_; +}; + +#if defined(UNDER_CE) +# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } } +#else // defined(UNDER_CE) +# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } } +#endif // defined(UNDER_CE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_static_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_STATIC_MUTEX_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_thread.hpp b/extern/asio-1.18.2/include/asio/detail/win_thread.hpp new file mode 100644 index 0000000..0f6679d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_thread.hpp @@ -0,0 +1,147 @@ +// +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_THREAD_HPP +#define ASIO_DETAIL_WIN_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) +ASIO_DECL void __stdcall apc_function(ULONG data); +#else +ASIO_DECL void __stdcall apc_function(ULONG_PTR data); +#endif + +template +class win_thread_base +{ +public: + static bool terminate_threads() + { + return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; + } + + static void set_terminate_threads(bool b) + { + ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); + } + +private: + static long terminate_threads_; +}; + +template +long win_thread_base::terminate_threads_ = 0; + +class win_thread + : private noncopyable, + public win_thread_base +{ +public: + // Constructor. + template + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) + { + start_thread(new func(f), stack_size); + } + + // Destructor. + ASIO_DECL ~win_thread(); + + // Wait for the thread to exit. + ASIO_DECL void join(); + + // Get number of CPUs. + ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) + friend ASIO_DECL void __stdcall apc_function(ULONG); +#else + friend ASIO_DECL void __stdcall apc_function(ULONG_PTR); +#endif + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + ::HANDLE entry_event_; + ::HANDLE exit_event_; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + + ::HANDLE thread_; + ::HANDLE exit_event_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_WIN_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/win_tss_ptr.hpp b/extern/asio-1.18.2/include/asio/detail/win_tss_ptr.hpp new file mode 100644 index 0000000..fa137a8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/win_tss_ptr.hpp @@ -0,0 +1,79 @@ +// +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WIN_TSS_PTR_HPP +#define ASIO_DETAIL_WIN_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +ASIO_DECL DWORD win_tss_ptr_create(); + +template +class win_tss_ptr + : private noncopyable +{ +public: + // Constructor. + win_tss_ptr() + : tss_key_(win_tss_ptr_create()) + { + } + + // Destructor. + ~win_tss_ptr() + { + ::TlsFree(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast(::TlsGetValue(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::TlsSetValue(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + DWORD tss_key_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winapp_thread.hpp b/extern/asio-1.18.2/include/asio/detail/winapp_thread.hpp new file mode 100644 index 0000000..512aa23 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winapp_thread.hpp @@ -0,0 +1,124 @@ +// +// detail/winapp_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINAPP_THREAD_HPP +#define ASIO_DETAIL_WINAPP_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI winapp_thread_function(LPVOID arg); + +class winapp_thread + : private noncopyable +{ +public: + // Constructor. + template + winapp_thread(Function f, unsigned int = 0) + { + scoped_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, winapp_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~winapp_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObjectEx(thread_, INFINITE, false); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetNativeSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI winapp_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI winapp_thread_function(LPVOID arg) +{ + scoped_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP) + +#endif // ASIO_DETAIL_WINAPP_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/wince_thread.hpp b/extern/asio-1.18.2/include/asio/detail/wince_thread.hpp new file mode 100644 index 0000000..63030f2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/wince_thread.hpp @@ -0,0 +1,124 @@ +// +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINCE_THREAD_HPP +#define ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && defined(UNDER_CE) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template + wince_thread(Function f, unsigned int = 0) + { + scoped_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + scoped_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && defined(UNDER_CE) + +#endif // ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_async_manager.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_async_manager.hpp new file mode 100644 index 0000000..ee7d4f6 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_async_manager.hpp @@ -0,0 +1,305 @@ +// +// detail/winrt_async_manager.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP +#define ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_async_manager + : public execution_context_service_base +{ +public: + // Constructor. + winrt_async_manager(execution_context& context) + : execution_context_service_base(context), + scheduler_(use_service(context)), + outstanding_ops_(1) + { + } + + // Destructor. + ~winrt_async_manager() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + if (--outstanding_ops_ > 0) + { + // Block until last operation is complete. + std::future f = promise_.get_future(); + f.wait(); + } + } + + void sync(Windows::Foundation::IAsyncAction^ action, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + action->Completed = ref new AsyncActionCompletedHandler( + [promise](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + action->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + } + + template + TResult sync(Windows::Foundation::IAsyncOperation^ operation, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + operation->Completed = ref new AsyncOperationCompletedHandler( + [promise](IAsyncOperation^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + operation->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + template + TResult sync( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + operation->Completed + = ref new AsyncOperationWithProgressCompletedHandler( + [promise](IAsyncOperationWithProgress^ operation, + AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Started: + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + operation->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + void async(Windows::Foundation::IAsyncAction^ action, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncActionCompletedHandler( + [this, handler](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + action->ErrorCode.Value, + asio::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + action->Completed = on_completed; + } + + template + void async(Windows::Foundation::IAsyncOperation^ operation, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncOperationCompletedHandler( + [this, handler](IAsyncOperation^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + operation->ErrorCode.Value, + asio::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + + template + void async( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed + = ref new AsyncOperationWithProgressCompletedHandler( + [this, handler](IAsyncOperationWithProgress< + TResult, TProgress>^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + operation->ErrorCode.Value, + asio::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + +private: + // The scheduler implementation used to post completed handlers. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Count of outstanding operations. + atomic_count outstanding_ops_; + + // Used to keep wait for outstanding operations to complete. + std::promise promise_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_async_op.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_async_op.hpp new file mode 100644 index 0000000..0751681 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_async_op.hpp @@ -0,0 +1,65 @@ +// +// detail/winrt_async_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_ASYNC_OP_HPP +#define ASIO_DETAIL_WINRT_ASYNC_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_async_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The result of the operation, to be passed to the completion handler. + TResult result_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func), + result_() + { + } +}; + +template <> +class winrt_async_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WINRT_ASYNC_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_resolve_op.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_resolve_op.hpp new file mode 100644 index 0000000..b7cfcb2 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_resolve_op.hpp @@ -0,0 +1,125 @@ +// +// detail/winrt_resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_RESOLVE_OP_HPP +#define ASIO_DETAIL_WINRT_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_resolve_op : + public winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^> +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef asio::ip::basic_resolver_query query_type; + typedef asio::ip::basic_resolver_results results_type; + + winrt_resolve_op(const query_type& query, + Handler& handler, const IoExecutor& io_ex) + : winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^>( + &winrt_resolve_op::do_complete), + query_(query), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_resolve_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + results_type results = results_type(); + if (!o->ec_) + { + try + { + results = results_type::create(o->result_, o->query_.hints(), + o->query_.host_name(), o->query_.service_name()); + } + catch (Platform::Exception^ e) + { + o->ec_ = asio::error_code(e->HResult, + asio::system_category()); + } + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, results); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + query_type query_; + Handler handler_; + handler_work executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_RESOLVE_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_resolver_service.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_resolver_service.hpp new file mode 100644 index 0000000..81ecb74 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_resolver_service.hpp @@ -0,0 +1,212 @@ +// +// detail/winrt_resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP +#define ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/post.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/winrt_async_manager.hpp" +#include "asio/detail/winrt_resolve_op.hpp" +#include "asio/detail/winrt_utils.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_resolver_service : + public execution_context_service_base > +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the asynchronous operation that the operation has been + // cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef asio::ip::basic_resolver_query query_type; + + // The results type. + typedef asio::ip::basic_resolver_results results_type; + + // Constructor. + winrt_resolver_service(execution_context& context) + : execution_context_service_base< + winrt_resolver_service >(context), + scheduler_(use_service(context)), + async_manager_(use_service(context)) + { + } + + // Destructor. + ~winrt_resolver_service() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Perform any fork-related housekeeping. + void notify_fork(execution_context::fork_event) + { + } + + // Construct a new resolver implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new resolver implementation. + void move_construct(implementation_type&, + implementation_type&) + { + } + + // Move-assign from another resolver implementation. + void move_assign(implementation_type&, + winrt_resolver_service&, implementation_type&) + { + } + + // Destroy a resolver implementation. + void destroy(implementation_type&) + { + } + + // Cancel pending asynchronous operations. + void cancel(implementation_type&) + { + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, + const query_type& query, asio::error_code& ec) + { + try + { + using namespace Windows::Networking::Sockets; + auto endpoint_pairs = async_manager_.sync( + DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), ec); + + if (ec) + return results_type(); + + return results_type::create( + endpoint_pairs, query.hints(), + query.host_name(), query.service_name()); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return results_type(); + } + } + + // Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_resolve_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(query, handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + (void)impl; + + try + { + using namespace Windows::Networking::Sockets; + async_manager_.async(DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), p.p); + p.v = p.p = 0; + } + catch (Platform::Exception^ e) + { + p.p->ec_ = asio::error_code( + e->HResult, asio::system_category()); + scheduler_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + } + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return results_type(); + } + + // Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const results_type results; + asio::post(io_ex, detail::bind_handler(handler, ec, results)); + } + +private: + // The scheduler implementation used for delivering completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + winrt_async_manager& async_manager_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_socket_connect_op.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_socket_connect_op.hpp new file mode 100644 index 0000000..b0e0fbf --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_socket_connect_op.hpp @@ -0,0 +1,98 @@ +// +// detail/winrt_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_socket_connect_op : + public winrt_async_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op); + + winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex) + : winrt_async_op(&winrt_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_connect_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_socket_recv_op.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_socket_recv_op.hpp new file mode 100644 index 0000000..722578e --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_socket_recv_op.hpp @@ -0,0 +1,119 @@ +// +// detail/winrt_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_socket_recv_op : + public winrt_async_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op); + + winrt_socket_recv_op(const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : winrt_async_op( + &winrt_socket_recv_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_recv_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0; + if (bytes_transferred == 0 && !o->ec_ && + !buffer_sequence_adapter::all_empty(o->buffers_)) + { + o->ec_ = asio::error::eof; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; + handler_work executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_socket_send_op.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_socket_send_op.hpp new file mode 100644 index 0000000..0f52d97 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_socket_send_op.hpp @@ -0,0 +1,110 @@ +// +// detail/winrt_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_socket_send_op : + public winrt_async_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op); + + winrt_socket_send_op(const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : winrt_async_op(&winrt_socket_send_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_send_op* o(static_cast(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work w( + ASIO_MOVE_CAST2(handler_work)( + o->work_)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->result_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; + handler_work executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service.hpp new file mode 100644 index 0000000..b7727ff --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service.hpp @@ -0,0 +1,250 @@ +// +// detail/winrt_ssocket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP +#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_socket_connect_op.hpp" +#include "asio/detail/winrt_ssocket_service_base.hpp" +#include "asio/detail/winrt_utils.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +class winrt_ssocket_service : + public execution_context_service_base >, + public winrt_ssocket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type; + + // The implementation type of the socket. + struct implementation_type : base_implementation_type + { + // Default constructor. + implementation_type() + : base_implementation_type(), + protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + winrt_ssocket_service(execution_context& context) + : execution_context_service_base >(context), + winrt_ssocket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) ASIO_NOEXCEPT + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + winrt_ssocket_service& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type& impl, + winrt_ssocket_service&, + typename winrt_ssocket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + try + { + impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket; + impl.protocol_ = protocol; + ec = asio::error_code(); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + impl.socket_ = native_socket; + impl.protocol_ = protocol; + ec = asio::error_code(); + + return ec; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + endpoint.resize(do_get_endpoint(impl, true, + endpoint.data(), endpoint.size(), ec)); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + endpoint.resize(do_get_endpoint(impl, false, + endpoint.data(), endpoint.size(), ec)); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(implementation_type&, + socket_base::shutdown_type, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + return do_set_option(impl, option.level(impl.protocol_), + option.name(impl.protocol_), option.data(impl.protocol_), + option.size(impl.protocol_), ec); + } + + // Get a socket option. + template + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + do_get_option(impl, option.level(impl.protocol_), + option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + return do_connect(impl, peer_endpoint.data(), ec); + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_connect_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "socket", &impl, 0, "async_connect")); + + start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service_base.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service_base.hpp new file mode 100644 index 0000000..6668975 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_ssocket_service_base.hpp @@ -0,0 +1,362 @@ +// +// detail/winrt_ssocket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winrt_async_manager.hpp" +#include "asio/detail/winrt_socket_recv_op.hpp" +#include "asio/detail/winrt_socket_send_op.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_ssocket_service_base +{ +public: + // The native type of a socket. + typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // Default constructor. + base_implementation_type() + : socket_(nullptr), + next_(0), + prev_(0) + { + } + + // The underlying native socket. + native_handle_type socket_; + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL winrt_ssocket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type&); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl) ASIO_NOEXCEPT; + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + winrt_ssocket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != nullptr; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL native_handle_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + asio::error_code cancel(base_implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return false; + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Perform an IO control command on the socket. + template + asio::error_code io_control(base_implementation_type&, + IO_Control_Command&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Send the given data to the peer. + template + std::size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return do_send(impl, + buffer_sequence_adapter::first(buffers), flags, ec); + } + + // Wait until data can be sent without blocking. + std::size_t send(base_implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_send_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "socket", &impl, 0, "async_send")); + + start_send_op(impl, + buffer_sequence_adapter::first(buffers), + flags, p.p, is_continuation); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, + detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Receive some data from the peer. Returns the number of bytes received. + template + std::size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return do_receive(impl, + buffer_sequence_adapter::first(buffers), flags, ec); + } + + // Wait until data can be received without blocking. + std::size_t receive(base_implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_recv_op op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "socket", &impl, 0, "async_receive")); + + start_receive_op(impl, + buffer_sequence_adapter::first(buffers), + flags, p.p, is_continuation); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + asio::post(io_ex, + detail::bind_handler(handler, ec, bytes_transferred)); + } + +protected: + // Helper function to obtain endpoints associated with the connection. + ASIO_DECL std::size_t do_get_endpoint( + const base_implementation_type& impl, bool local, + void* addr, std::size_t addr_len, asio::error_code& ec) const; + + // Helper function to set a socket option. + ASIO_DECL asio::error_code do_set_option( + base_implementation_type& impl, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec); + + // Helper function to get a socket option. + ASIO_DECL void do_get_option( + const base_implementation_type& impl, + int level, int optname, void* optval, + std::size_t* optlen, asio::error_code& ec) const; + + // Helper function to perform a synchronous connect. + ASIO_DECL asio::error_code do_connect( + base_implementation_type& impl, + const void* addr, asio::error_code& ec); + + // Helper function to start an asynchronous connect. + ASIO_DECL void start_connect_op( + base_implementation_type& impl, const void* addr, + winrt_async_op* op, bool is_continuation); + + // Helper function to perform a synchronous send. + ASIO_DECL std::size_t do_send( + base_implementation_type& impl, const asio::const_buffer& data, + socket_base::message_flags flags, asio::error_code& ec); + + // Helper function to start an asynchronous send. + ASIO_DECL void start_send_op(base_implementation_type& impl, + const asio::const_buffer& data, socket_base::message_flags flags, + winrt_async_op* op, bool is_continuation); + + // Helper function to perform a synchronous receive. + ASIO_DECL std::size_t do_receive( + base_implementation_type& impl, const asio::mutable_buffer& data, + socket_base::message_flags flags, asio::error_code& ec); + + // Helper function to start an asynchronous receive. + ASIO_DECL void start_receive_op(base_implementation_type& impl, + const asio::mutable_buffer& data, socket_base::message_flags flags, + winrt_async_op* op, + bool is_continuation); + + // The scheduler implementation used for delivering completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // The manager that keeps track of outstanding operations. + winrt_async_manager& async_manager_; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winrt_ssocket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_timer_scheduler.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..8fd9636 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_timer_scheduler.hpp @@ -0,0 +1,147 @@ +// +// detail/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include +#include "asio/detail/event.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/thread.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_timer_scheduler + : public execution_context_service_base +{ +public: + // Constructor. + ASIO_DECL winrt_timer_scheduler(execution_context& context); + + // Destructor. + ASIO_DECL ~winrt_timer_scheduler(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); + + // Initialise the task. No effect as this class uses its own thread. + ASIO_DECL void init_task(); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from); + +private: + // Run the select loop in the thread. + ASIO_DECL void run_thread(); + + // Entry point for the select loop thread. + ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // The scheduler implementation used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Mutex used to protect internal variables. + asio::detail::mutex mutex_; + + // Event used to wake up background thread. + asio::detail::event event_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The background thread that is waiting for timers to expire. + asio::detail::thread* thread_; + + // Does the background thread need to stop. + bool stop_thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/winrt_timer_scheduler.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winrt_timer_scheduler.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winrt_utils.hpp b/extern/asio-1.18.2/include/asio/detail/winrt_utils.hpp new file mode 100644 index 0000000..d0e1840 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winrt_utils.hpp @@ -0,0 +1,106 @@ +// +// detail/winrt_utils.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINRT_UTILS_HPP +#define ASIO_DETAIL_WINRT_UTILS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include "asio/buffer.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace winrt_utils { + +inline Platform::String^ string(const char* from) +{ + std::wstring tmp(from, from + std::strlen(from)); + return ref new Platform::String(tmp.c_str()); +} + +inline Platform::String^ string(const std::string& from) +{ + std::wstring tmp(from.begin(), from.end()); + return ref new Platform::String(tmp.c_str()); +} + +inline std::string string(Platform::String^ from) +{ + std::wstring_convert> converter; + return converter.to_bytes(from->Data()); +} + +inline Platform::String^ string(unsigned short from) +{ + return string(std::to_string(from)); +} + +template +inline Platform::String^ string(const T& from) +{ + return string(from.to_string()); +} + +inline int integer(Platform::String^ from) +{ + return _wtoi(from->Data()); +} + +template +inline Windows::Networking::HostName^ host_name(const T& from) +{ + return ref new Windows::Networking::HostName((string)(from)); +} + +template +inline Windows::Storage::Streams::IBuffer^ buffer_dup( + const ConstBufferSequence& buffers) +{ + using Microsoft::WRL::ComPtr; + using asio::buffer_size; + std::size_t size = buffer_size(buffers); + auto b = ref new Windows::Storage::Streams::Buffer(size); + ComPtr insp = reinterpret_cast(b); + ComPtr bacc; + insp.As(&bacc); + byte* bytes = nullptr; + bacc->Buffer(&bytes); + asio::buffer_copy(asio::buffer(bytes, size), buffers); + b->Length = size; + return b; +} + +} // namespace winrt_utils +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_UTILS_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/winsock_init.hpp b/extern/asio-1.18.2/include/asio/detail/winsock_init.hpp new file mode 100644 index 0000000..a9e361a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/winsock_init.hpp @@ -0,0 +1,128 @@ +// +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WINSOCK_INIT_HPP +#define ASIO_DETAIL_WINSOCK_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winsock_init_base +{ +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data + { + long init_count_; + long result_; + }; + + ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + ASIO_DECL static void manual_startup(data& d); + + ASIO_DECL static void cleanup(data& d); + + ASIO_DECL static void manual_cleanup(data& d); + + ASIO_DECL static void throw_on_error(data& d); +}; + +template +class winsock_init : private winsock_init_base +{ +public: + winsock_init(bool allow_throw = true) + { + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) + { + startup(data_, Major, Minor); + throw_on_error(data_); + } + + ~winsock_init() + { + cleanup(data_); + } + + // This class may be used to indicate that user code will manage Winsock + // initialisation and cleanup. This may be required in the case of a DLL, for + // example, where it is not safe to initialise Winsock from global object + // constructors. + // + // To prevent asio from initialising Winsock, the object must be constructed + // before any Asio's own global objects. With MSVC, this may be accomplished + // by adding the following code to the DLL: + // + // #pragma warning(push) + // #pragma warning(disable:4073) + // #pragma init_seg(lib) + // asio::detail::winsock_init<>::manual manual_winsock_init; + // #pragma warning(pop) + class manual + { + public: + manual() + { + manual_startup(data_); + } + + manual(const manual&) + { + manual_startup(data_); + } + + ~manual() + { + manual_cleanup(data_); + } + }; + +private: + friend class manual; + static data data_; +}; + +template +winsock_init_base::data winsock_init::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winsock_init.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/work_dispatcher.hpp b/extern/asio-1.18.2/include/asio/detail/work_dispatcher.hpp new file mode 100644 index 0000000..836605f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/work_dispatcher.hpp @@ -0,0 +1,148 @@ +// +// detail/work_dispatcher.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WORK_DISPATCHER_HPP +#define ASIO_DETAIL_WORK_DISPATCHER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/prefer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template +struct is_work_dispatcher_required : true_type +{ +}; + +template +struct is_work_dispatcher_required::asio_associated_executor_is_unspecialised, + void + >::value + >::type> : false_type +{ +}; + +template +class work_dispatcher +{ +public: + template + work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler, + const Executor& handler_ex) + : handler_(ASIO_MOVE_CAST(CompletionHandler)(handler)), + executor_(asio::prefer(handler_ex, + execution::outstanding_work.tracked)) + { + } + +#if defined(ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : handler_(other.handler_), + executor_(other.executor_) + { + } + + work_dispatcher(work_dispatcher&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + executor_(ASIO_MOVE_CAST(work_executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + execution::execute( + asio::prefer(executor_, + execution::blocking.possibly, + execution::allocator((get_associated_allocator)(handler_))), + ASIO_MOVE_CAST(Handler)(handler_)); + } + +private: + typedef typename decay< + typename prefer_result::type + >::type work_executor_type; + + Handler handler_; + work_executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template +class work_dispatcher::value>::type> +{ +public: + template + work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler, + const Executor& handler_ex) + : work_(handler_ex), + handler_(ASIO_MOVE_CAST(CompletionHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : work_(other.work_), + handler_(other.handler_) + { + } + + work_dispatcher(work_dispatcher&& other) + : work_(ASIO_MOVE_CAST(executor_work_guard)(other.work_)), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + typename associated_allocator::type alloc( + (get_associated_allocator)(handler_)); + work_.get_executor().dispatch( + ASIO_MOVE_CAST(Handler)(handler_), alloc); + work_.reset(); + } + +private: + executor_work_guard work_; + Handler handler_; +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WORK_DISPATCHER_HPP diff --git a/extern/asio-1.18.2/include/asio/detail/wrapped_handler.hpp b/extern/asio-1.18.2/include/asio/detail/wrapped_handler.hpp new file mode 100644 index 0000000..18ca6d3 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/detail/wrapped_handler.hpp @@ -0,0 +1,327 @@ +// +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DETAIL_WRAPPED_HANDLER_HPP +#define ASIO_DETAIL_WRAPPED_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct is_continuation_delegated +{ + template + bool operator()(Dispatcher&, Handler& handler) const + { + return asio_handler_cont_helpers::is_continuation(handler); + } +}; + +struct is_continuation_if_running +{ + template + bool operator()(Dispatcher& dispatcher, Handler&) const + { + return dispatcher.running_in_this_thread(); + } +}; + +template +class wrapped_handler +{ +public: + typedef void result_type; + + wrapped_handler(Dispatcher dispatcher, Handler& handler) + : dispatcher_(dispatcher), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + wrapped_handler(const wrapped_handler& other) + : dispatcher_(other.dispatcher_), + handler_(other.handler_) + { + } + + wrapped_handler(wrapped_handler&& other) + : dispatcher_(other.dispatcher_), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_)); + } + + void operator()() const + { + dispatcher_.dispatch(handler_); + } + + template + void operator()(const Arg1& arg1) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template + void operator()(const Arg1& arg1) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + +//private: + Dispatcher dispatcher_; + Handler handler_; +}; + +template +class rewrapped_handler +{ +public: + explicit rewrapped_handler(Handler& handler, const Context& context) + : context_(context), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + + explicit rewrapped_handler(const Handler& handler, const Context& context) + : context_(context), + handler_(handler) + { + } + +#if defined(ASIO_HAS_MOVE) + rewrapped_handler(const rewrapped_handler& other) + : context_(other.context_), + handler_(other.handler_) + { + } + + rewrapped_handler(rewrapped_handler&& other) + : context_(ASIO_MOVE_CAST(Context)(other.context_)), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(); + } + + void operator()() const + { + handler_(); + } + +//private: + Context context_; + Handler handler_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + wrapped_handler* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + wrapped_handler* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + wrapped_handler* this_handler) +{ + return IsContinuation()(this_handler->dispatcher_, this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + wrapped_handler* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler( + function, this_handler->handler_)); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + wrapped_handler* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler( + function, this_handler->handler_)); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + rewrapped_handler* this_handler) +{ +#if defined(ASIO_NO_DEPRECATED) + asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(ASIO_NO_DEPRECATED) + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + rewrapped_handler* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->context_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + rewrapped_handler* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->context_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + rewrapped_handler* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + rewrapped_handler* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +#if defined(ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(ASIO_NO_DEPRECATED) +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP diff --git a/extern/asio-1.18.2/include/asio/dispatch.hpp b/extern/asio-1.18.2/include/asio/dispatch.hpp new file mode 100644 index 0000000..64da41b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/dispatch.hpp @@ -0,0 +1,121 @@ +// +// dispatch.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_DISPATCH_HPP +#define ASIO_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution_context.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object may be called from the current thread prior to + * returning from dispatch(). Otherwise, it is queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex by performing + * get_associated_executor(handler). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Performs ex.dispatch(std::move(handler), alloc). + * + * @li Returns result.get(). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( + ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object may be called from the current thread prior to returning + * from dispatch(). Otherwise, it is queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * get_associated_executor(handler). + * + * @li Creates a work object @c w by performing make_work(ex1). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Constructs a function object @c f with a function call operator that + * performs ex1.dispatch(std::move(handler), alloc) followed by + * w.reset(). + * + * @li Performs Executor(ex).dispatch(std::move(f), alloc). + * + * @li Returns result.get(). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, + ASIO_MOVE_ARG(CompletionToken) token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename constraint< + execution::is_executor::value || is_executor::value + >::type = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns dispatch(ctx.get_executor(), + * forward(token)). + */ +template +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, + ASIO_MOVE_ARG(CompletionToken) token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename constraint::value>::type = 0); + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/dispatch.hpp" + +#endif // ASIO_DISPATCH_HPP diff --git a/extern/asio-1.18.2/include/asio/error.hpp b/extern/asio-1.18.2/include/asio/error.hpp new file mode 100644 index 0000000..8b4decd --- /dev/null +++ b/extern/asio-1.18.2/include/asio/error.hpp @@ -0,0 +1,356 @@ +// +// error.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ERROR_HPP +#define ASIO_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" +#include "asio/system_error.hpp" +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(ASIO_WINDOWS_RUNTIME) +# include +#else +# include +# include +#endif + +#if defined(GENERATING_DOCUMENTATION) +/// INTERNAL ONLY. +# define ASIO_NATIVE_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define ASIO_SOCKET_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define ASIO_NETDB_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define ASIO_GETADDRINFO_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined +#elif defined(ASIO_WINDOWS_RUNTIME) +# define ASIO_NATIVE_ERROR(e) __HRESULT_FROM_WIN32(e) +# define ASIO_SOCKET_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define ASIO_NETDB_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define ASIO_GETADDRINFO_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# define ASIO_NATIVE_ERROR(e) e +# define ASIO_SOCKET_ERROR(e) WSA ## e +# define ASIO_NETDB_ERROR(e) WSA ## e +# define ASIO_GETADDRINFO_ERROR(e) WSA ## e +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win +#else +# define ASIO_NATIVE_ERROR(e) e +# define ASIO_SOCKET_ERROR(e) e +# define ASIO_NETDB_ERROR(e) e +# define ASIO_GETADDRINFO_ERROR(e) e +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { + +enum basic_errors +{ + /// Permission denied. + access_denied = ASIO_SOCKET_ERROR(EACCES), + + /// Address family not supported by protocol. + address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), + + /// Address already in use. + address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), + + /// Transport endpoint is already connected. + already_connected = ASIO_SOCKET_ERROR(EISCONN), + + /// Operation already in progress. + already_started = ASIO_SOCKET_ERROR(EALREADY), + + /// Broken pipe. + broken_pipe = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE), + ASIO_NATIVE_ERROR(EPIPE)), + + /// A connection has been aborted. + connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED), + + /// Connection refused. + connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED), + + /// Connection reset by peer. + connection_reset = ASIO_SOCKET_ERROR(ECONNRESET), + + /// Bad file descriptor. + bad_descriptor = ASIO_SOCKET_ERROR(EBADF), + + /// Bad address. + fault = ASIO_SOCKET_ERROR(EFAULT), + + /// No route to host. + host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH), + + /// Operation now in progress. + in_progress = ASIO_SOCKET_ERROR(EINPROGRESS), + + /// Interrupted system call. + interrupted = ASIO_SOCKET_ERROR(EINTR), + + /// Invalid argument. + invalid_argument = ASIO_SOCKET_ERROR(EINVAL), + + /// Message too long. + message_size = ASIO_SOCKET_ERROR(EMSGSIZE), + + /// The name was too long. + name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG), + + /// Network is down. + network_down = ASIO_SOCKET_ERROR(ENETDOWN), + + /// Network dropped connection on reset. + network_reset = ASIO_SOCKET_ERROR(ENETRESET), + + /// Network is unreachable. + network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH), + + /// Too many open files. + no_descriptors = ASIO_SOCKET_ERROR(EMFILE), + + /// No buffer space available. + no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS), + + /// Cannot allocate memory. + no_memory = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), + ASIO_NATIVE_ERROR(ENOMEM)), + + /// Operation not permitted. + no_permission = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), + ASIO_NATIVE_ERROR(EPERM)), + + /// Protocol not available. + no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT), + + /// No such device. + no_such_device = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_BAD_UNIT), + ASIO_NATIVE_ERROR(ENODEV)), + + /// Transport endpoint is not connected. + not_connected = ASIO_SOCKET_ERROR(ENOTCONN), + + /// Socket operation on non-socket. + not_socket = ASIO_SOCKET_ERROR(ENOTSOCK), + + /// Operation cancelled. + operation_aborted = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), + ASIO_NATIVE_ERROR(ECANCELED)), + + /// Operation not supported. + operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP), + + /// Cannot send after transport endpoint shutdown. + shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN), + + /// Connection timed out. + timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT), + + /// Resource temporarily unavailable. + try_again = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_RETRY), + ASIO_NATIVE_ERROR(EAGAIN)), + + /// The socket is marked non-blocking and the requested operation would block. + would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK) +}; + +enum netdb_errors +{ + /// Host not found (authoritative). + host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND), + + /// Host not found (non-authoritative). + host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN), + + /// The query is valid but does not have associated address data. + no_data = ASIO_NETDB_ERROR(NO_DATA), + + /// A non-recoverable error occurred. + no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY) +}; + +enum addrinfo_errors +{ + /// The service is not supported for the given socket type. + service_not_found = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), + ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), + + /// The socket type is not supported. + socket_type_not_supported = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), + ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)) +}; + +enum misc_errors +{ + /// Already open. + already_open = 1, + + /// End of file or stream. + eof, + + /// Element not found. + not_found, + + /// The descriptor cannot fit into the select system call's fd_set. + fd_set_failure +}; + +inline const asio::error_category& get_system_category() +{ + return asio::system_category(); +} + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +extern ASIO_DECL +const asio::error_category& get_netdb_category(); + +extern ASIO_DECL +const asio::error_category& get_addrinfo_category(); + +#else // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +inline const asio::error_category& get_netdb_category() +{ + return get_system_category(); +} + +inline const asio::error_category& get_addrinfo_category() +{ + return get_system_category(); +} + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +extern ASIO_DECL +const asio::error_category& get_misc_category(); + +static const asio::error_category& + system_category ASIO_UNUSED_VARIABLE + = asio::error::get_system_category(); +static const asio::error_category& + netdb_category ASIO_UNUSED_VARIABLE + = asio::error::get_netdb_category(); +static const asio::error_category& + addrinfo_category ASIO_UNUSED_VARIABLE + = asio::error::get_addrinfo_category(); +static const asio::error_category& + misc_category ASIO_UNUSED_VARIABLE + = asio::error::get_misc_category(); + +} // namespace error +} // namespace asio + +#if defined(ASIO_HAS_STD_SYSTEM_ERROR) +namespace std { + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +} // namespace std +#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +namespace asio { +namespace error { + +inline asio::error_code make_error_code(basic_errors e) +{ + return asio::error_code( + static_cast(e), get_system_category()); +} + +inline asio::error_code make_error_code(netdb_errors e) +{ + return asio::error_code( + static_cast(e), get_netdb_category()); +} + +inline asio::error_code make_error_code(addrinfo_errors e) +{ + return asio::error_code( + static_cast(e), get_addrinfo_category()); +} + +inline asio::error_code make_error_code(misc_errors e) +{ + return asio::error_code( + static_cast(e), get_misc_category()); +} + +} // namespace error +namespace stream_errc { + // Simulates the proposed stream_errc scoped enum. + using error::eof; + using error::not_found; +} // namespace stream_errc +namespace socket_errc { + // Simulates the proposed socket_errc scoped enum. + using error::already_open; + using error::not_found; +} // namespace socket_errc +namespace resolver_errc { + // Simulates the proposed resolver_errc scoped enum. + using error::host_not_found; + const error::netdb_errors try_again = error::host_not_found_try_again; + using error::service_not_found; +} // namespace resolver_errc +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#undef ASIO_NATIVE_ERROR +#undef ASIO_SOCKET_ERROR +#undef ASIO_NETDB_ERROR +#undef ASIO_GETADDRINFO_ERROR +#undef ASIO_WIN_OR_POSIX + +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_ERROR_HPP diff --git a/extern/asio-1.18.2/include/asio/error_code.hpp b/extern/asio-1.18.2/include/asio/error_code.hpp new file mode 100644 index 0000000..4026b9c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/error_code.hpp @@ -0,0 +1,202 @@ +// +// error_code.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_ERROR_CODE_HPP +#define ASIO_ERROR_CODE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_SYSTEM_ERROR) +# include +#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) +# include +# include "asio/detail/noncopyable.hpp" +# if !defined(ASIO_NO_IOSTREAM) +# include +# endif // !defined(ASIO_NO_IOSTREAM) +#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_HAS_STD_SYSTEM_ERROR) + +typedef std::error_category error_category; + +#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +/// Base class for all error categories. +class error_category : private noncopyable +{ +public: + /// Destructor. + virtual ~error_category() + { + } + + /// Returns a string naming the error gategory. + virtual const char* name() const = 0; + + /// Returns a string describing the error denoted by @c value. + virtual std::string message(int value) const = 0; + + /// Equality operator to compare two error categories. + bool operator==(const error_category& rhs) const + { + return this == &rhs; + } + + /// Inequality operator to compare two error categories. + bool operator!=(const error_category& rhs) const + { + return !(*this == rhs); + } +}; + +#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +/// Returns the error category used for the system errors produced by asio. +extern ASIO_DECL const error_category& system_category(); + +#if defined(ASIO_HAS_STD_SYSTEM_ERROR) + +typedef std::error_code error_code; + +#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +/// Class to represent an error code value. +class error_code +{ +public: + /// Default constructor. + error_code() + : value_(0), + category_(&system_category()) + { + } + + /// Construct with specific error code and category. + error_code(int v, const error_category& c) + : value_(v), + category_(&c) + { + } + + /// Construct from an error code enum. + template + error_code(ErrorEnum e) + { + *this = make_error_code(e); + } + + /// Clear the error value to the default. + void clear() + { + value_ = 0; + category_ = &system_category(); + } + + /// Assign a new error value. + void assign(int v, const error_category& c) + { + value_ = v; + category_ = &c; + } + + /// Get the error value. + int value() const + { + return value_; + } + + /// Get the error category. + const error_category& category() const + { + return *category_; + } + + /// Get the message associated with the error. + std::string message() const + { + return category_->message(value_); + } + + struct unspecified_bool_type_t + { + }; + + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + + static void unspecified_bool_true(unspecified_bool_type_t) {} + + /// Operator returns non-null if there is a non-success error code. + operator unspecified_bool_type() const + { + if (value_ == 0) + return 0; + else + return &error_code::unspecified_bool_true; + } + + /// Operator to test if the error represents success. + bool operator!() const + { + return value_ == 0; + } + + /// Equality operator to compare two error objects. + friend bool operator==(const error_code& e1, const error_code& e2) + { + return e1.value_ == e2.value_ && e1.category_ == e2.category_; + } + + /// Inequality operator to compare two error objects. + friend bool operator!=(const error_code& e1, const error_code& e2) + { + return e1.value_ != e2.value_ || e1.category_ != e2.category_; + } + +private: + // The value associated with the error code. + int value_; + + // The category associated with the error code. + const error_category* category_; +}; + +# if !defined(ASIO_NO_IOSTREAM) + +/// Output an error code. +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const error_code& ec) +{ + os << ec.category().name() << ':' << ec.value(); + return os; +} + +# endif // !defined(ASIO_NO_IOSTREAM) + +#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/error_code.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_ERROR_CODE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution.hpp b/extern/asio-1.18.2/include/asio/execution.hpp new file mode 100644 index 0000000..861b25b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution.hpp @@ -0,0 +1,48 @@ +// +// execution.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_HPP +#define ASIO_EXECUTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/execution/allocator.hpp" +#include "asio/execution/any_executor.hpp" +#include "asio/execution/bad_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/blocking_adaptation.hpp" +#include "asio/execution/bulk_execute.hpp" +#include "asio/execution/bulk_guarantee.hpp" +#include "asio/execution/connect.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/context_as.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/execution/mapping.hpp" +#include "asio/execution/occupancy.hpp" +#include "asio/execution/operation_state.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/execution/prefer_only.hpp" +#include "asio/execution/receiver.hpp" +#include "asio/execution/receiver_invocation_error.hpp" +#include "asio/execution/relationship.hpp" +#include "asio/execution/schedule.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/execution/set_value.hpp" +#include "asio/execution/start.hpp" +#include "asio/execution/submit.hpp" + +#endif // ASIO_EXECUTION_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/allocator.hpp b/extern/asio-1.18.2/include/asio/execution/allocator.hpp new file mode 100644 index 0000000..ea4d56c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/allocator.hpp @@ -0,0 +1,337 @@ +// +// execution/allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_ALLOCATOR_HPP +#define ASIO_EXECUTION_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe which allocator an executor will use to allocate the +/// memory required to store a submitted function object. +template +struct allocator_t +{ + /// The allocator_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The allocator_t property can be required. + static constexpr bool is_requirable = true; + + /// The allocator_t property can be preferred. + static constexpr bool is_preferable = true; + + /// Default constructor. + constexpr allocator_t(); + + /// Obtain the allocator stored in the allocator_t property object. + /** + * Present only if @c ProtoAllocator is non-void. + */ + constexpr ProtoAllocator value() const; + + /// Create an allocator_t object with a different allocator. + /** + * Present only if @c ProtoAllocator is void. + */ + template + allocator_t allocator; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template +struct allocator_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, allocator_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = allocator_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + ASIO_CONSTEXPR ProtoAllocator value() const + { + return a_; + } + +private: + friend struct allocator_t; + + explicit ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a) + : a_(a) + { + } + + ProtoAllocator a_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T allocator_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <> +struct allocator_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + + ASIO_CONSTEXPR allocator_t() + { + } + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, allocator_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = allocator_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + ASIO_CONSTEXPR allocator_t operator()( + const OtherProtoAllocator& a) const + { + return allocator_t(a); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template +const T allocator_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr allocator_t allocator; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +template +struct allocator_instance +{ + static allocator_t instance; +}; + +template +allocator_t allocator_instance::instance; + +namespace { +static const allocator_t& allocator = allocator_instance::instance; +} // namespace +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property > + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query, + typename enable_if< + execution::allocator_t::template + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::allocator_t::template + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::allocator_t::template + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_ALLOCATOR_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/any_executor.hpp b/extern/asio-1.18.2/include/asio/execution/any_executor.hpp new file mode 100644 index 0000000..cce1646 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/any_executor.hpp @@ -0,0 +1,2346 @@ +// +// execution/any_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_ANY_EXECUTOR_HPP +#define ASIO_EXECUTION_ANY_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include +#include "asio/detail/assert.hpp" +#include "asio/detail/cstddef.hpp" +#include "asio/detail/executor_function.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/throw_exception.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/execution/bad_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// Polymorphic executor wrapper. +template +class any_executor +{ +public: + /// Default constructor. + any_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + any_executor(nullptr_t) noexcept; + + /// Copy constructor. + any_executor(const any_executor& e) noexcept; + + /// Move constructor. + any_executor(any_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. + template + any_executor(any_executor e); + + /// Construct a polymorphic wrapper for the specified executor. + template + any_executor(Executor e); + + /// Assignment operator. + any_executor& operator=(const any_executor& e) noexcept; + + /// Move assignment operator. + any_executor& operator=(any_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + any_executor& operator=(nullptr_t); + + /// Assignment operator to create a polymorphic wrapper for the specified + /// executor. + template + any_executor& operator=(Executor e); + + /// Destructor. + ~any_executor(); + + /// Swap targets with another polymorphic wrapper. + void swap(any_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code execution::any_executor ex = ...; + * auto ex2 = asio::requre(ex, execution::blocking.possibly); @endcode + */ + template + any_executor require(Property) const; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code execution::any_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template + any_executor prefer(Property) const; + + /// Obtain the value associated with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code execution::any_executor ex = ...; + * size_t n = asio::query(ex, execution::occupancy); @endcode + */ + template + typename Property::polymorphic_query_result_type query(Property) const; + + /// Execute the function on the target executor. + /** + * Do not call this function directly. It is intended for use with the + * execution::execute customisation point. + * + * For example: + * @code execution::any_executor<> ex = ...; + * execution::execute(ex, my_function_object); @endcode + * + * Throws asio::bad_executor if the polymorphic wrapper has no target. + */ + template + void execute(Function&& f) const; + + /// Obtain the underlying execution context. + /** + * This function is provided for backward compatibility. It is automatically + * defined when the @c SupportableProperties... list includes a property of + * type execution::context_as, for some type U. + */ + automatically_determined context() const; + + /// Determine whether the wrapper has a target executor. + /** + * @returns @c true if the polymorphic wrapper has a target executor, + * otherwise false. + */ + explicit operator bool() const noexcept; + + /// Get the type of the target executor. + const type_info& target_type() const noexcept; + + /// Get a pointer to the target executor. + template Executor* target() noexcept; + + /// Get a pointer to the target executor. + template const Executor* target() const noexcept; +}; + +/// Equality operator. +/** + * @relates any_executor + */ +template +bool operator==(const any_executor& a, + const any_executor& b) noexcept; + +/// Equality operator. +/** + * @relates any_executor + */ +template +bool operator==(const any_executor& a, + nullptr_t) noexcept; + +/// Equality operator. +/** + * @relates any_executor + */ +template +bool operator==(nullptr_t, + const any_executor& b) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template +bool operator!=(const any_executor& a, + const any_executor& b) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template +bool operator!=(const any_executor& a, + nullptr_t) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template +bool operator!=(nullptr_t, + const any_executor& b) noexcept; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) +#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor; + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) + +template +struct context_as_t; + +namespace detail { + +// Traits used to detect whether a property is requirable or preferable, taking +// into account that T::is_requirable or T::is_preferable may not not be well +// formed. + +template +struct is_requirable : false_type {}; + +template +struct is_requirable::type> : + true_type {}; + +template +struct is_preferable : false_type {}; + +template +struct is_preferable::type> : + true_type {}; + +// Trait used to detect context_as property, for backward compatibility. + +template +struct is_context_as : false_type {}; + +template +struct is_context_as > : true_type {}; + +// Helper template to: +// - Check if a target can supply the supportable properties. +// - Find the first convertible-from-T property in the list. + +template +struct supportable_properties; + +template +struct supportable_properties +{ + template + struct is_valid_target : integral_constant::value + ? can_require::value + : true + ) + && + ( + is_preferable::value + ? can_prefer::value + : true + ) + && + ( + !is_requirable::value && !is_preferable::value + ? can_query::value + : true + ) + > + { + }; + + struct found + { + ASIO_STATIC_CONSTEXPR(bool, value = true); + typedef Prop type; + typedef typename Prop::polymorphic_query_result_type query_result_type; + ASIO_STATIC_CONSTEXPR(std::size_t, index = I); + }; + + struct not_found + { + ASIO_STATIC_CONSTEXPR(bool, value = false); + }; + + template + struct find_convertible_property : + conditional< + is_same::value || is_convertible::value, + found, + not_found + >::type {}; + + template + struct find_convertible_requirable_property : + conditional< + is_requirable::value + && (is_same::value || is_convertible::value), + found, + not_found + >::type {}; + + template + struct find_convertible_preferable_property : + conditional< + is_preferable::value + && (is_same::value || is_convertible::value), + found, + not_found + >::type {}; + + struct find_context_as_property : + conditional< + is_context_as::value, + found, + not_found + >::type {}; +}; + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct supportable_properties +{ + template + struct is_valid_target : integral_constant::template is_valid_target::value + && + supportable_properties::template is_valid_target::value + ) + > + { + }; + + template + struct find_convertible_property : + conditional< + is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_property + >::type {}; + + template + struct find_convertible_requirable_property : + conditional< + is_requirable::value + && is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_requirable_property + >::type {}; + + template + struct find_convertible_preferable_property : + conditional< + is_preferable::value + && is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_preferable_property + >::type {}; + + struct find_context_as_property : + conditional< + is_context_as::value, + typename supportable_properties::found, + typename supportable_properties::find_context_as_property + >::type {}; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \ + template \ + struct supportable_properties \ + { \ + template \ + struct is_valid_target : integral_constant::template is_valid_target::value \ + && \ + supportable_properties::template \ + is_valid_target::value \ + ) \ + > \ + { \ + }; \ + \ + template \ + struct find_convertible_property : \ + conditional< \ + is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_property \ + >::type {}; \ + \ + template \ + struct find_convertible_requirable_property : \ + conditional< \ + is_requirable::value \ + && is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_requirable_property \ + >::type {}; \ + \ + template \ + struct find_convertible_preferable_property : \ + conditional< \ + is_preferable::value \ + && is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_preferable_property \ + >::type {}; \ + \ + struct find_context_as_property : \ + conditional< \ + is_context_as::value, \ + typename supportable_properties::found, \ + typename supportable_properties::find_context_as_property \ + >::type {}; \ + }; \ + /**/ +ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct is_valid_target_executor : + conditional< + is_executor::value, + typename supportable_properties<0, Props>::template is_valid_target, + false_type + >::type +{ +}; + +class any_executor_base +{ +public: + any_executor_base() ASIO_NOEXCEPT + : object_fns_(object_fns_table()), + target_(0), + target_fns_(target_fns_table()) + { + } + + template + any_executor_base(Executor ex, false_type) + : target_fns_(target_fns_table( + any_executor_base::query_blocking(ex, + can_query()) + == execution::blocking.always)) + { + any_executor_base::construct_object(ex, + integral_constant::value <= alignment_of::value + >()); + } + + template + any_executor_base(Executor other, true_type) + : object_fns_(object_fns_table >()), + target_fns_(other.target_fns_) + { + asio::detail::shared_ptr p = + asio::detail::make_shared( + ASIO_MOVE_CAST(Executor)(other)); + target_ = p->template target(); + new (&object_) asio::detail::shared_ptr( + ASIO_MOVE_CAST(asio::detail::shared_ptr)(p)); + } + + any_executor_base(const any_executor_base& other) ASIO_NOEXCEPT + : object_fns_(other.object_fns_), + target_fns_(other.target_fns_) + { + object_fns_->copy(*this, other); + } + + ~any_executor_base() ASIO_NOEXCEPT + { + object_fns_->destroy(*this); + } + + any_executor_base& operator=( + const any_executor_base& other) ASIO_NOEXCEPT + { + if (this != &other) + { + object_fns_->destroy(*this); + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + object_fns_->copy(*this, other); + } + return *this; + } + + any_executor_base& operator=(nullptr_t) ASIO_NOEXCEPT + { + object_fns_->destroy(*this); + target_ = 0; + object_fns_ = object_fns_table(); + target_fns_ = target_fns_table(); + return *this; + } + +#if defined(ASIO_HAS_MOVE) + + any_executor_base(any_executor_base&& other) ASIO_NOEXCEPT + : object_fns_(other.object_fns_), + target_fns_(other.target_fns_) + { + other.object_fns_ = object_fns_table(); + other.target_fns_ = target_fns_table(); + object_fns_->move(*this, other); + other.target_ = 0; + } + + any_executor_base& operator=( + any_executor_base&& other) ASIO_NOEXCEPT + { + if (this != &other) + { + object_fns_->destroy(*this); + object_fns_ = other.object_fns_; + other.object_fns_ = object_fns_table(); + target_fns_ = other.target_fns_; + other.target_fns_ = target_fns_table(); + object_fns_->move(*this, other); + other.target_ = 0; + } + return *this; + } + +#endif // defined(ASIO_HAS_MOVE) + + void swap(any_executor_base& other) ASIO_NOEXCEPT + { + if (this != &other) + { + any_executor_base tmp(ASIO_MOVE_CAST(any_executor_base)(other)); + other = ASIO_MOVE_CAST(any_executor_base)(*this); + *this = ASIO_MOVE_CAST(any_executor_base)(tmp); + } + } + + template + void execute(ASIO_MOVE_ARG(F) f) const + { + if (target_fns_->blocking_execute != 0) + { + asio::detail::non_const_lvalue f2(f); + target_fns_->blocking_execute(*this, function_view(f2.value)); + } + else + { + target_fns_->execute(*this, + function(ASIO_MOVE_CAST(F)(f), std::allocator())); + } + } + + template + Executor* target() + { + return static_cast(target_); + } + + template + const Executor* target() const + { + return static_cast(target_); + } + +#if !defined(ASIO_NO_TYPEID) + const std::type_info& target_type() const +#else // !defined(ASIO_NO_TYPEID) + const void* target_type() const +#endif // !defined(ASIO_NO_TYPEID) + { + return target_fns_->target_type(); + } + + struct unspecified_bool_type_t {}; + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + static void unspecified_bool_true(unspecified_bool_type_t) {} + + operator unspecified_bool_type() const ASIO_NOEXCEPT + { + return target_ ? &any_executor_base::unspecified_bool_true : 0; + } + + bool operator!() const ASIO_NOEXCEPT + { + return target_ == 0; + } + +protected: + bool equality_helper(const any_executor_base& other) const ASIO_NOEXCEPT + { + if (target_ == other.target_) + return true; + if (target_ && !other.target_) + return false; + if (!target_ && other.target_) + return false; + if (target_fns_ != other.target_fns_) + return false; + return target_fns_->equal(*this, other); + } + + template + Ex& object() + { + return *static_cast(static_cast(&object_)); + } + + template + const Ex& object() const + { + return *static_cast(static_cast(&object_)); + } + + struct object_fns + { + void (*destroy)(any_executor_base&); + void (*copy)(any_executor_base&, const any_executor_base&); + void (*move)(any_executor_base&, any_executor_base&); + const void* (*target)(const any_executor_base&); + }; + + static void destroy_void(any_executor_base&) + { + } + + static void copy_void(any_executor_base& ex1, const any_executor_base&) + { + ex1.target_ = 0; + } + + static void move_void(any_executor_base& ex1, any_executor_base&) + { + ex1.target_ = 0; + } + + static const void* target_void(const any_executor_base&) + { + return 0; + } + + template + static const object_fns* object_fns_table( + typename enable_if< + is_same::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_void, + &any_executor_base::copy_void, + &any_executor_base::move_void, + &any_executor_base::target_void + }; + return &fns; + } + + static void destroy_shared(any_executor_base& ex) + { + typedef asio::detail::shared_ptr type; + ex.object().~type(); + } + + static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) + { + typedef asio::detail::shared_ptr type; + new (&ex1.object_) type(ex2.object()); + ex1.target_ = ex2.target_; + } + + static void move_shared(any_executor_base& ex1, any_executor_base& ex2) + { + typedef asio::detail::shared_ptr type; + new (&ex1.object_) type(ASIO_MOVE_CAST(type)(ex2.object())); + ex1.target_ = ex2.target_; + ex2.object().~type(); + } + + static const void* target_shared(const any_executor_base& ex) + { + typedef asio::detail::shared_ptr type; + return ex.object().get(); + } + + template + static const object_fns* object_fns_table( + typename enable_if< + is_same >::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_shared, + &any_executor_base::copy_shared, + &any_executor_base::move_shared, + &any_executor_base::target_shared + }; + return &fns; + } + + template + static void destroy_object(any_executor_base& ex) + { + ex.object().~Obj(); + } + + template + static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) + { + new (&ex1.object_) Obj(ex2.object()); + ex1.target_ = &ex1.object(); + } + + template + static void move_object(any_executor_base& ex1, any_executor_base& ex2) + { + new (&ex1.object_) Obj(ASIO_MOVE_CAST(Obj)(ex2.object())); + ex1.target_ = &ex1.object(); + ex2.object().~Obj(); + } + + template + static const void* target_object(const any_executor_base& ex) + { + return &ex.object(); + } + + template + static const object_fns* object_fns_table( + typename enable_if< + !is_same::value + && !is_same >::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_object, + &any_executor_base::copy_object, + &any_executor_base::move_object, + &any_executor_base::target_object + }; + return &fns; + } + + typedef asio::detail::executor_function function; + typedef asio::detail::executor_function_view function_view; + + struct target_fns + { +#if !defined(ASIO_NO_TYPEID) + const std::type_info& (*target_type)(); +#else // !defined(ASIO_NO_TYPEID) + const void* (*target_type)(); +#endif // !defined(ASIO_NO_TYPEID) + bool (*equal)(const any_executor_base&, const any_executor_base&); + void (*execute)(const any_executor_base&, ASIO_MOVE_ARG(function)); + void (*blocking_execute)(const any_executor_base&, function_view); + }; + +#if !defined(ASIO_NO_TYPEID) + static const std::type_info& target_type_void() + { + return typeid(void); + } +#else // !defined(ASIO_NO_TYPEID) + static const void* target_type_void() + { + return 0; + } +#endif // !defined(ASIO_NO_TYPEID) + + static bool equal_void(const any_executor_base&, const any_executor_base&) + { + return true; + } + + static void execute_void(const any_executor_base&, + ASIO_MOVE_ARG(function)) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + + static void blocking_execute_void(const any_executor_base&, function_view) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + + template + static const target_fns* target_fns_table( + typename enable_if< + is_same::value + >::type* = 0) + { + static const target_fns fns = + { + &any_executor_base::target_type_void, + &any_executor_base::equal_void, + &any_executor_base::execute_void, + &any_executor_base::blocking_execute_void + }; + return &fns; + } + +#if !defined(ASIO_NO_TYPEID) + template + static const std::type_info& target_type_ex() + { + return typeid(Ex); + } +#else // !defined(ASIO_NO_TYPEID) + template + static const void* target_type_ex() + { + static int unique_id; + return &unique_id; + } +#endif // !defined(ASIO_NO_TYPEID) + + template + static bool equal_ex(const any_executor_base& ex1, + const any_executor_base& ex2) + { + return *ex1.target() == *ex2.target(); + } + + template + static void execute_ex(const any_executor_base& ex, + ASIO_MOVE_ARG(function) f) + { + execution::execute(*ex.target(), ASIO_MOVE_CAST(function)(f)); + } + + template + static void blocking_execute_ex(const any_executor_base& ex, function_view f) + { + execution::execute(*ex.target(), f); + } + + template + static const target_fns* target_fns_table(bool is_always_blocking, + typename enable_if< + !is_same::value + >::type* = 0) + { + static const target_fns fns_with_execute = + { + &any_executor_base::target_type_ex, + &any_executor_base::equal_ex, + &any_executor_base::execute_ex, + 0 + }; + + static const target_fns fns_with_blocking_execute = + { + &any_executor_base::target_type_ex, + &any_executor_base::equal_ex, + 0, + &any_executor_base::blocking_execute_ex + }; + + return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute; + } + +#if defined(ASIO_MSVC) +# pragma warning (push) +# pragma warning (disable:4702) +#endif // defined(ASIO_MSVC) + + static void query_fn_void(void*, const void*, const void*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + + template + static void query_fn_non_void(void*, const void* ex, const void* prop, + typename enable_if< + asio::can_query::value + && is_same::value + >::type*) + { + asio::query(*static_cast(ex), + *static_cast(prop)); + } + + template + static void query_fn_non_void(void*, const void*, const void*, + typename enable_if< + !asio::can_query::value + && is_same::value + >::type*) + { + } + + template + static void query_fn_non_void(void* result, const void* ex, const void* prop, + typename enable_if< + asio::can_query::value + && !is_same::value + && is_reference::value + >::type*) + { + *static_cast::type**>(result) + = &static_cast( + asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_non_void(void*, const void*, const void*, + typename enable_if< + !asio::can_query::value + && !is_same::value + && is_reference::value + >::type*) + { + std::terminate(); // Combination should not be possible. + } + + template + static void query_fn_non_void(void* result, const void* ex, const void* prop, + typename enable_if< + asio::can_query::value + && !is_same::value + && is_scalar::value + >::type*) + { + *static_cast(result) + = static_cast( + asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_non_void(void* result, const void*, const void*, + typename enable_if< + !asio::can_query::value + && !is_same::value + && is_scalar::value + >::type*) + { + *static_cast(result) + = typename Prop::polymorphic_query_result_type(); + } + + template + static void query_fn_non_void(void* result, const void* ex, const void* prop, + typename enable_if< + asio::can_query::value + && !is_same::value + && !is_reference::value + && !is_scalar::value + >::type*) + { + *static_cast(result) + = new typename Prop::polymorphic_query_result_type( + asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_non_void(void* result, const void*, const void*, ...) + { + *static_cast(result) + = new typename Prop::polymorphic_query_result_type(); + } + + template + static void query_fn_impl(void* result, const void* ex, const void* prop, + typename enable_if< + is_same::value + >::type*) + { + query_fn_void(result, ex, prop); + } + + template + static void query_fn_impl(void* result, const void* ex, const void* prop, + typename enable_if< + !is_same::value + >::type*) + { + query_fn_non_void(result, ex, prop, 0); + } + + template + static void query_fn(void* result, const void* ex, const void* prop) + { + query_fn_impl(result, ex, prop, 0); + } + + template + static Poly require_fn_impl(const void*, const void*, + typename enable_if< + is_same::value + >::type*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + return Poly(); + } + + template + static Poly require_fn_impl(const void* ex, const void* prop, + typename enable_if< + !is_same::value && Prop::is_requirable + >::type*) + { + return asio::require(*static_cast(ex), + *static_cast(prop)); + } + + template + static Poly require_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template + static Poly require_fn(const void* ex, const void* prop) + { + return require_fn_impl(ex, prop, 0); + } + + template + static Poly prefer_fn_impl(const void*, const void*, + typename enable_if< + is_same::value + >::type*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + return Poly(); + } + + template + static Poly prefer_fn_impl(const void* ex, const void* prop, + typename enable_if< + !is_same::value && Prop::is_preferable + >::type*) + { + return asio::prefer(*static_cast(ex), + *static_cast(prop)); + } + + template + static Poly prefer_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template + static Poly prefer_fn(const void* ex, const void* prop) + { + return prefer_fn_impl(ex, prop, 0); + } + + template + struct prop_fns + { + void (*query)(void*, const void*, const void*); + Poly (*require)(const void*, const void*); + Poly (*prefer)(const void*, const void*); + }; + +#if defined(ASIO_MSVC) +# pragma warning (pop) +#endif // defined(ASIO_MSVC) + +private: + template + static execution::blocking_t query_blocking(const Executor& ex, true_type) + { + return asio::query(ex, execution::blocking); + } + + template + static execution::blocking_t query_blocking(const Executor&, false_type) + { + return execution::blocking_t(); + } + + template + void construct_object(Executor& ex, true_type) + { + object_fns_ = object_fns_table(); + target_ = new (&object_) Executor(ASIO_MOVE_CAST(Executor)(ex)); + } + + template + void construct_object(Executor& ex, false_type) + { + object_fns_ = object_fns_table >(); + asio::detail::shared_ptr p = + asio::detail::make_shared( + ASIO_MOVE_CAST(Executor)(ex)); + target_ = p.get(); + new (&object_) asio::detail::shared_ptr( + ASIO_MOVE_CAST(asio::detail::shared_ptr)(p)); + } + +/*private:*/public: +// template friend class any_executor; + + typedef aligned_storage< + sizeof(asio::detail::shared_ptr), + alignment_of >::value + >::type object_type; + + object_type object_; + const object_fns* object_fns_; + void* target_; + const target_fns* target_fns_; +}; + +template +struct any_executor_context +{ +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template +struct any_executor_context::type> +{ + typename Property::query_result_type context() const + { + return static_cast(this)->query(typename Property::type()); + } +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +} // namespace detail + +template <> +class any_executor<> : public detail::any_executor_base +{ +public: + any_executor() ASIO_NOEXCEPT + : detail::any_executor_base() + { + } + + any_executor(nullptr_t) ASIO_NOEXCEPT + : detail::any_executor_base() + { + } + + template + any_executor(Executor ex, + typename enable_if< + conditional< + !is_same::value + && !is_base_of::value, + is_executor, + false_type + >::type::value + >::type* = 0) + : detail::any_executor_base( + ASIO_MOVE_CAST(Executor)(ex), false_type()) + { + } + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + any_executor(any_executor other) + : detail::any_executor_base( + static_cast(other)) + { + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + any_executor(any_executor other) + : detail::any_executor_base( + static_cast(other)) + { + } + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + any_executor(const any_executor& other) ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast(other)) + { + } + + any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT + { + if (this != &other) + { + detail::any_executor_base::operator=( + static_cast(other)); + } + return *this; + } + + any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT + { + detail::any_executor_base::operator=(p); + return *this; + } + +#if defined(ASIO_HAS_MOVE) + + any_executor(any_executor&& other) ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast( + static_cast(other))) + { + } + + any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT + { + if (this != &other) + { + detail::any_executor_base::operator=( + static_cast( + static_cast(other))); + } + return *this; + } + +#endif // defined(ASIO_HAS_MOVE) + + void swap(any_executor& other) ASIO_NOEXCEPT + { + detail::any_executor_base::swap( + static_cast(other)); + } + + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT + { + return any_executor_base::equality_helper(other); + } + + template + friend typename enable_if< + is_same::value + || is_same::value, + bool + >::type operator==(const AnyExecutor1& a, + const AnyExecutor2& b) ASIO_NOEXCEPT + { + return static_cast(a).equality_helper(b); + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator==(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT + { + return !a; + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator==(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT + { + return !b; + } + + template + friend typename enable_if< + is_same::value + || is_same::value, + bool + >::type operator!=(const AnyExecutor1& a, + const AnyExecutor2& b) ASIO_NOEXCEPT + { + return !static_cast(a).equality_helper(b); + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator!=(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT + { + return !!a; + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator!=(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT + { + return !!b; + } +}; + +inline void swap(any_executor<>& a, any_executor<>& b) ASIO_NOEXCEPT +{ + return a.swap(b); +} + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor : + public detail::any_executor_base, + public detail::any_executor_context< + any_executor, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::find_context_as_property> +{ +public: + any_executor() ASIO_NOEXCEPT + : detail::any_executor_base(), + prop_fns_(prop_fns_table()) + { + } + + any_executor(nullptr_t) ASIO_NOEXCEPT + : detail::any_executor_base(), + prop_fns_(prop_fns_table()) + { + } + + template + any_executor(Executor ex, + typename enable_if< + conditional< + !is_same::value + && !is_base_of::value, + detail::is_valid_target_executor< + Executor, void(SupportableProperties...)>, + false_type + >::type::value + >::type* = 0) + : detail::any_executor_base( + ASIO_MOVE_CAST(Executor)(ex), false_type()), + prop_fns_(prop_fns_table()) + { + } + + template + any_executor(any_executor other, + typename enable_if< + conditional< + !is_same< + any_executor, + any_executor + >::value, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::template is_valid_target< + any_executor >, + false_type + >::type::value + >::type* = 0) + : detail::any_executor_base(ASIO_MOVE_CAST( + any_executor)(other), true_type()), + prop_fns_(prop_fns_table >()) + { + } + + any_executor(const any_executor& other) ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast(other)), + prop_fns_(other.prop_fns_) + { + } + + any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast(other)); + } + return *this; + } + + any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT + { + prop_fns_ = prop_fns_table(); + detail::any_executor_base::operator=(p); + return *this; + } + +#if defined(ASIO_HAS_MOVE) + + any_executor(any_executor&& other) ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast( + static_cast(other))), + prop_fns_(other.prop_fns_) + { + other.prop_fns_ = prop_fns_table(); + } + + any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast( + static_cast(other))); + } + return *this; + } + +#endif // defined(ASIO_HAS_MOVE) + + void swap(any_executor& other) ASIO_NOEXCEPT + { + if (this != &other) + { + detail::any_executor_base::swap( + static_cast(other)); + const prop_fns* tmp_prop_fns = other.prop_fns_; + other.prop_fns_ = prop_fns_; + prop_fns_ = tmp_prop_fns; + } + } + + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT + { + return any_executor_base::equality_helper(other); + } + + template + friend typename enable_if< + is_same::value + || is_same::value, + bool + >::type operator==(const AnyExecutor1& a, + const AnyExecutor2& b) ASIO_NOEXCEPT + { + return static_cast(a).equality_helper(b); + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator==(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT + { + return !a; + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator==(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT + { + return !b; + } + + template + friend typename enable_if< + is_same::value + || is_same::value, + bool + >::type operator!=(const AnyExecutor1& a, + const AnyExecutor2& b) ASIO_NOEXCEPT + { + return !static_cast(a).equality_helper(b); + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator!=(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT + { + return !!a; + } + + template + friend typename enable_if< + is_same::value, + bool + >::type operator!=(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT + { + return !!b; + } + + template + struct find_convertible_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property {}; + + template + void query(const Property& p, + typename enable_if< + is_same< + typename find_convertible_property::query_result_type, + void + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + prop_fns_[found::index].query(0, object_fns_->target(*this), + &static_cast(p)); + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + is_reference< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename remove_reference< + typename found::query_result_type>::type* result = 0; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return *result; + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + is_scalar< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename found::query_result_type result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return result; + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + !is_reference< + typename find_convertible_property::query_result_type + >::value + && + !is_scalar< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename found::query_result_type* result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return *asio::detail::scoped_ptr< + typename found::query_result_type>(result); + } + + template + struct find_convertible_requirable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property {}; + + template + any_executor require(const Property& p, + typename enable_if< + find_convertible_requirable_property::value + >::type* = 0) const + { + typedef find_convertible_requirable_property found; + return prop_fns_[found::index].require(object_fns_->target(*this), + &static_cast(p)); + } + + template + struct find_convertible_preferable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property {}; + + template + any_executor prefer(const Property& p, + typename enable_if< + find_convertible_preferable_property::value + >::type* = 0) const + { + typedef find_convertible_preferable_property found; + return prop_fns_[found::index].prefer(object_fns_->target(*this), + &static_cast(p)); + } + +//private: + template + static const prop_fns* prop_fns_table() + { + static const prop_fns fns[] = + { + { + &detail::any_executor_base::query_fn< + Ex, SupportableProperties>, + &detail::any_executor_base::require_fn< + any_executor, Ex, SupportableProperties>, + &detail::any_executor_base::prefer_fn< + any_executor, Ex, SupportableProperties> + }... + }; + return fns; + } + + const prop_fns* prop_fns_; +}; + +template +inline void swap(any_executor& a, + any_executor& b) ASIO_NOEXCEPT +{ + return a.swap(b); +} + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n + +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } + +#if defined(ASIO_HAS_MOVE) + +# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ + any_executor(any_executor&& other) ASIO_NOEXCEPT \ + : detail::any_executor_base( \ + static_cast( \ + static_cast(other))), \ + prop_fns_(other.prop_fns_) \ + { \ + other.prop_fns_ = prop_fns_table(); \ + } \ + \ + any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT \ + { \ + if (this != &other) \ + { \ + prop_fns_ = other.prop_fns_; \ + detail::any_executor_base::operator=( \ + static_cast( \ + static_cast(other))); \ + } \ + return *this; \ + } \ + /**/ +#else // defined(ASIO_HAS_MOVE) + +# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS + +#endif // defined(ASIO_HAS_MOVE) + +#define ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \ + template \ + class any_executor : \ + public detail::any_executor_base, \ + public detail::any_executor_context< \ + any_executor, \ + typename detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \ + { \ + public: \ + any_executor() ASIO_NOEXCEPT \ + : detail::any_executor_base(), \ + prop_fns_(prop_fns_table()) \ + { \ + } \ + \ + any_executor(nullptr_t) ASIO_NOEXCEPT \ + : detail::any_executor_base(), \ + prop_fns_(prop_fns_table()) \ + { \ + } \ + \ + template \ + any_executor(Executor ex, \ + typename enable_if< \ + conditional< \ + !is_same::value \ + && !is_base_of::value, \ + detail::is_valid_target_executor< \ + Executor, void(ASIO_VARIADIC_TARGS(n))>, \ + false_type \ + >::type::value \ + >::type* = 0) \ + : detail::any_executor_base(ASIO_MOVE_CAST( \ + Executor)(ex), false_type()), \ + prop_fns_(prop_fns_table()) \ + { \ + } \ + \ + any_executor(const any_executor& other) ASIO_NOEXCEPT \ + : detail::any_executor_base( \ + static_cast(other)), \ + prop_fns_(other.prop_fns_) \ + { \ + } \ + \ + any_executor(any_executor<> other) \ + : detail::any_executor_base(ASIO_MOVE_CAST( \ + any_executor<>)(other), true_type()), \ + prop_fns_(prop_fns_table >()) \ + { \ + } \ + \ + template \ + any_executor(OtherAnyExecutor other, \ + typename enable_if< \ + conditional< \ + !is_same::value \ + && is_base_of::value, \ + typename detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + is_valid_target, \ + false_type \ + >::type::value \ + >::type* = 0) \ + : detail::any_executor_base(ASIO_MOVE_CAST( \ + OtherAnyExecutor)(other), true_type()), \ + prop_fns_(prop_fns_table()) \ + { \ + } \ + \ + any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT \ + { \ + if (this != &other) \ + { \ + prop_fns_ = other.prop_fns_; \ + detail::any_executor_base::operator=( \ + static_cast(other)); \ + } \ + return *this; \ + } \ + \ + any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT \ + { \ + prop_fns_ = prop_fns_table(); \ + detail::any_executor_base::operator=(p); \ + return *this; \ + } \ + \ + ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ + \ + void swap(any_executor& other) ASIO_NOEXCEPT \ + { \ + if (this != &other) \ + { \ + detail::any_executor_base::swap( \ + static_cast(other)); \ + const prop_fns* tmp_prop_fns = other.prop_fns_; \ + other.prop_fns_ = prop_fns_; \ + prop_fns_ = tmp_prop_fns; \ + } \ + } \ + \ + using detail::any_executor_base::execute; \ + using detail::any_executor_base::target; \ + using detail::any_executor_base::target_type; \ + using detail::any_executor_base::operator unspecified_bool_type; \ + using detail::any_executor_base::operator!; \ + \ + bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT \ + { \ + return any_executor_base::equality_helper(other); \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value \ + || is_same::value, \ + bool \ + >::type operator==(const AnyExecutor1& a, \ + const AnyExecutor2& b) ASIO_NOEXCEPT \ + { \ + return static_cast(a).equality_helper(b); \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value, \ + bool \ + >::type operator==(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT \ + { \ + return !a; \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value, \ + bool \ + >::type operator==(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT \ + { \ + return !b; \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value \ + || is_same::value, \ + bool \ + >::type operator!=(const AnyExecutor1& a, \ + const AnyExecutor2& b) ASIO_NOEXCEPT \ + { \ + return !static_cast(a).equality_helper(b); \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value, \ + bool \ + >::type operator!=(const AnyExecutor& a, nullptr_t) ASIO_NOEXCEPT \ + { \ + return !!a; \ + } \ + \ + template \ + friend typename enable_if< \ + is_same::value, \ + bool \ + >::type operator!=(nullptr_t, const AnyExecutor& b) ASIO_NOEXCEPT \ + { \ + return !!b; \ + } \ + \ + template \ + struct find_convertible_property : \ + detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property {}; \ + \ + template \ + void query(const Property& p, \ + typename enable_if< \ + is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + prop_fns_[found::index].query(0, object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + is_reference< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename remove_reference< \ + typename found::query_result_type>::type* result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return *result; \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + is_scalar< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename found::query_result_type result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return result; \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + !is_reference< \ + typename find_convertible_property::query_result_type \ + >::value \ + && \ + !is_scalar< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename found::query_result_type* result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return *asio::detail::scoped_ptr< \ + typename found::query_result_type>(result); \ + } \ + \ + template \ + struct find_convertible_requirable_property : \ + detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_requirable_property {}; \ + \ + template \ + any_executor require(const Property& p, \ + typename enable_if< \ + find_convertible_requirable_property::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_requirable_property found; \ + return prop_fns_[found::index].require(object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + struct find_convertible_preferable_property : \ + detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_preferable_property {}; \ + \ + template \ + any_executor prefer(const Property& p, \ + typename enable_if< \ + find_convertible_preferable_property::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_preferable_property found; \ + return prop_fns_[found::index].prefer(object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + static const prop_fns* prop_fns_table() \ + { \ + static const prop_fns fns[] = \ + { \ + ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ + }; \ + return fns; \ + } \ + \ + const prop_fns* prop_fns_; \ + typedef detail::supportable_properties<0, \ + void(ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \ + }; \ + \ + template \ + inline void swap(any_executor& a, \ + any_executor& b) ASIO_NOEXCEPT \ + { \ + return a.swap(b); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_DEF +#undef ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 +#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 + +#endif // if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct equality_comparable > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <> +struct equality_comparable > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#define ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF(n) \ + template \ + struct equality_comparable< \ + execution::any_executor > \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = true; \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE( + ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct execute_member, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct execute_member, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#define ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \ + template \ + struct execute_member< \ + execution::any_executor, F> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef void result_type; \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE( + ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct query_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef typename execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property::query_result_type result_type; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \ + template \ + struct query_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef typename execution::detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property::query_result_type result_type; \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct require_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef execution::any_executor result_type; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \ + template \ + struct require_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_requirable_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef execution::any_executor result_type; \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE( + ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct prefer_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef execution::any_executor result_type; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \ + template \ + struct prefer_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_preferable_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef execution::any_executor result_type; \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF) +#undef ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_ANY_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/bad_executor.hpp b/extern/asio-1.18.2/include/asio/execution/bad_executor.hpp new file mode 100644 index 0000000..0532cef --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/bad_executor.hpp @@ -0,0 +1,47 @@ +// +// execution/bad_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_BAD_EXECUTOR_HPP +#define ASIO_EXECUTION_BAD_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +/// Exception thrown when trying to access an empty polymorphic executor. +class bad_executor + : public std::exception +{ +public: + /// Constructor. + ASIO_DECL bad_executor() ASIO_NOEXCEPT; + + /// Obtain message associated with exception. + ASIO_DECL virtual const char* what() const + ASIO_NOEXCEPT_OR_NOTHROW; +}; + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/execution/impl/bad_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_EXECUTION_BAD_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/blocking.hpp b/extern/asio-1.18.2/include/asio/execution/blocking.hpp new file mode 100644 index 0000000..76a2eb5 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/blocking.hpp @@ -0,0 +1,1551 @@ +// +// execution/blocking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_BLOCKING_HPP +#define ASIO_EXECUTION_BLOCKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the blocking +/// behaviour of their execution functions. +struct blocking_t +{ + /// The blocking_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level blocking_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// A sub-property that indicates that invocation of an executor's execution + /// function may block pending completion of one or more invocations of the + /// submitted function object. + struct possibly_t + { + /// The blocking_t::possibly_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The blocking_t::possibly_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::possibly_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr possibly_t(); + + /// Get the value associated with a property object. + /** + * @returns possibly_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall block until completion of all invocations of the submitted + /// function object. + struct always_t + { + /// The blocking_t::always_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The blocking_t::always_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::always_t property can be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr always_t(); + + /// Get the value associated with a property object. + /** + * @returns always_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall not block pending completion of the invocations of the + /// submitted function object. + struct never_t + { + /// The blocking_t::never_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The blocking_t::never_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::never_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr never_t(); + + /// Get the value associated with a property object. + /** + * @returns never_t(); + */ + static constexpr blocking_t value(); + }; + + /// A special value used for accessing the blocking_t::possibly_t property. + static constexpr possibly_t possibly; + + /// A special value used for accessing the blocking_t::always_t property. + static constexpr always_t always; + + /// A special value used for accessing the blocking_t::never_t property. + static constexpr never_t never; + + /// Default constructor. + constexpr blocking_t(); + + /// Construct from a sub-property value. + constexpr blocking_t(possibly_t); + + /// Construct from a sub-property value. + constexpr blocking_t(always_t); + + /// Construct from a sub-property value. + constexpr blocking_t(never_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_t& a, const blocking_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_t& a, const blocking_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_t property. +constexpr blocking_t blocking; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking { + +template struct possibly_t; +template struct always_t; +template struct never_t; + +} // namespace blocking +namespace blocking_adaptation { + +template struct allowed_t; + +template +void blocking_execute( + ASIO_MOVE_ARG(Executor) ex, + ASIO_MOVE_ARG(Function) func); + +} // namespace blocking_adaptation + +template +struct blocking_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_t polymorphic_query_result_type; + + typedef detail::blocking::possibly_t possibly_t; + typedef detail::blocking::always_t always_t; + typedef detail::blocking::never_t never_t; + + ASIO_CONSTEXPR blocking_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR blocking_t(possibly_t) + : value_(0) + { + } + + ASIO_CONSTEXPR blocking_t(always_t) + : value_(1) + { + } + + ASIO_CONSTEXPR blocking_t(never_t) + : value_(2) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, blocking_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, blocking_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = blocking_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const blocking_t& a, const blocking_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const blocking_t& a, const blocking_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_t + { + ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {} + }; + + template + friend ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::possibly_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, possibly_t()); + } + + template + friend ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::always_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, always_t()); + } + + template + friend ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::never_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, never_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const blocking_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T blocking_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const blocking_t blocking_t::instance; +#endif + +template +const typename blocking_t::possibly_t blocking_t::possibly; + +template +const typename blocking_t::always_t blocking_t::always; + +template +const typename blocking_t::never_t blocking_t::never; + +namespace blocking { + +template +struct possibly_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_t polymorphic_query_result_type; + + ASIO_CONSTEXPR possibly_t() + { + } + + template + struct query_member : + traits::query_member< + typename blocking_t::template proxy::type, possibly_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t::template static_proxy::type, possibly_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR possibly_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return possibly_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = possibly_t::static_query(); +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR blocking_t value() + { + return possibly_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const possibly_t&, const possibly_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const possibly_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const possibly_t&, const always_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const always_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const possibly_t&, const never_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const never_t&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T possibly_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +class adapter +{ +public: + adapter(int, const Executor& e) ASIO_NOEXCEPT + : executor_(e) + { + } + + adapter(const adapter& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + adapter(adapter&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + template + static ASIO_CONSTEXPR always_t query( + blocking_t) ASIO_NOEXCEPT + { + return always_t(); + } + + template + static ASIO_CONSTEXPR always_t query( + possibly_t) ASIO_NOEXCEPT + { + return always_t(); + } + + template + static ASIO_CONSTEXPR always_t query( + always_t) ASIO_NOEXCEPT + { + return always_t(); + } + + template + static ASIO_CONSTEXPR always_t query( + never_t) ASIO_NOEXCEPT + { + return always_t(); + } + + template + typename enable_if< + can_query::value, + typename query_result::type + >::type query(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) + { + return asio::query(executor_, p); + } + + template + typename enable_if< + can_require >::value, + typename require_result >::type + >::type require(possibly_t) const ASIO_NOEXCEPT + { + return asio::require(executor_, possibly_t()); + } + + template + typename enable_if< + can_require >::value, + typename require_result >::type + >::type require(never_t) const ASIO_NOEXCEPT + { + return asio::require(executor_, never_t()); + } + + template + typename enable_if< + can_require::value, + adapter::type + >::type> + >::type require(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_require::value)) + { + return adapter::type + >::type>(0, asio::require(executor_, p)); + } + + template + typename enable_if< + can_prefer::value, + adapter::type + >::type> + >::type prefer(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_prefer::value)) + { + return adapter::type + >::type>(0, asio::prefer(executor_, p)); + } + + template + typename enable_if< + execution::can_execute::value + >::type execute(ASIO_MOVE_ARG(Function) f) const + { + blocking_adaptation::blocking_execute( + executor_, ASIO_MOVE_CAST(Function)(f)); + } + + friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT + { + return a.executor_ == b.executor_; + } + + friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT + { + return a.executor_ != b.executor_; + } + +private: + Executor executor_; +}; + +template +struct always_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_t polymorphic_query_result_type; + + ASIO_CONSTEXPR always_t() + { + } + + template + struct query_member : + traits::query_member< + typename blocking_t::template proxy::type, always_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t::template static_proxy::type, always_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = always_t::static_query(); +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR blocking_t value() + { + return always_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const always_t&, const always_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const always_t&, const always_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const always_t&, const possibly_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const always_t&, const possibly_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const always_t&, const never_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const always_t&, const never_t&) + { + return true; + } + + template + friend adapter require( + const Executor& e, const always_t&, + typename enable_if< + is_executor::value + >::type* = 0, + typename enable_if< + traits::static_require< + const Executor&, + blocking_adaptation::allowed_t<0> + >::is_valid + >::type* = 0) + { + return adapter(0, e); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T always_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct never_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_t polymorphic_query_result_type; + + ASIO_CONSTEXPR never_t() + { + } + + template + struct query_member : + traits::query_member< + typename blocking_t::template proxy::type, never_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t::template static_proxy::type, never_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = never_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR blocking_t value() + { + return never_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const never_t&, const never_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const never_t&, const never_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const never_t&, const possibly_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const never_t&, const possibly_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const never_t&, const always_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const never_t&, const always_t&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T never_t::static_query_v; +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace blocking +} // namespace detail + +typedef detail::blocking_t<> blocking_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr blocking_t blocking; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const blocking_t& blocking = blocking_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::blocking_t::query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking::possibly_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_t::possibly_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking::always_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking::always_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking::never_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking::never_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::possibly_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::always_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::never_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free_default::type>::value + && execution::is_executor::value + && traits::static_require< + const T&, + execution::detail::blocking_adaptation::allowed_t<0> + >::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef execution::detail::blocking::adapter result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template +struct equality_comparable< + execution::detail::blocking::adapter > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + execution::detail::blocking::adapter, Function> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + execution::detail::blocking::adapter, + execution::detail::blocking_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_t::always_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + execution::detail::blocking::adapter, + execution::detail::blocking::always_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_t::always_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + execution::detail::blocking::adapter, + execution::detail::blocking::possibly_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_t::always_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + execution::detail::blocking::adapter, + execution::detail::blocking::never_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_t::always_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + execution::detail::blocking::adapter, Property, + typename enable_if< + can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + typedef typename query_result::type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + execution::detail::blocking::adapter, + execution::detail::blocking::possibly_t, + typename enable_if< + can_require< + const Executor&, + execution::detail::blocking::possibly_t + >::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_require >::value)); + typedef typename require_result >::type result_type; +}; + +template +struct require_member< + execution::detail::blocking::adapter, + execution::detail::blocking::never_t, + typename enable_if< + can_require< + const Executor&, + execution::detail::blocking::never_t + >::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_require >::value)); + typedef typename require_result >::type result_type; +}; + +template +struct require_member< + execution::detail::blocking::adapter, Property, + typename enable_if< + can_require::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_require::value)); + typedef execution::detail::blocking::adapter::type + >::type> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member< + execution::detail::blocking::adapter, Property, + typename enable_if< + can_prefer::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_prefer::value)); + typedef execution::detail::blocking::adapter::type + >::type> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BLOCKING_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/blocking_adaptation.hpp b/extern/asio-1.18.2/include/asio/execution/blocking_adaptation.hpp new file mode 100644 index 0000000..2a3fe90 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/blocking_adaptation.hpp @@ -0,0 +1,1212 @@ +// +// execution/blocking_adaptation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP +#define ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" +#include "asio/traits/prefer_member.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/require_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether automatic adaptation of an executor is +/// allowed in order to apply the blocking_adaptation_t::allowed_t property. +struct blocking_adaptation_t +{ + /// The blocking_adaptation_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level blocking_adaptation_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_adaptation_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// A sub-property that indicates that automatic adaptation is not allowed. + struct disallowed_t + { + /// The blocking_adaptation_t::disallowed_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The blocking_adaptation_t::disallowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::disallowed_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr disallowed_t(); + + /// Get the value associated with a property object. + /** + * @returns disallowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A sub-property that indicates that automatic adaptation is allowed. + struct allowed_t + { + /// The blocking_adaptation_t::allowed_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The blocking_adaptation_t::allowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::allowed_t property can be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr allowed_t(); + + /// Get the value associated with a property object. + /** + * @returns allowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A special value used for accessing the blocking_adaptation_t::disallowed_t + /// property. + static constexpr disallowed_t disallowed; + + /// A special value used for accessing the blocking_adaptation_t::allowed_t + /// property. + static constexpr allowed_t allowed; + + /// Default constructor. + constexpr blocking_adaptation_t(); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(disallowed_t); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(allowed_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_adaptation_t property. +constexpr blocking_adaptation_t blocking_adaptation; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking_adaptation { + +template struct disallowed_t; +template struct allowed_t; + +} // namespace blocking_adaptation + +template +struct blocking_adaptation_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_adaptation_t polymorphic_query_result_type; + + typedef detail::blocking_adaptation::disallowed_t disallowed_t; + typedef detail::blocking_adaptation::allowed_t allowed_t; + + ASIO_CONSTEXPR blocking_adaptation_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t) + : value_(0) + { + } + + ASIO_CONSTEXPR blocking_adaptation_t(allowed_t) + : value_(1) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, blocking_adaptation_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, blocking_adaptation_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = blocking_adaptation_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_adaptation_t + { + ASIO_CONSTEXPR convertible_from_blocking_adaptation_t( + blocking_adaptation_t) + { + } + }; + + template + friend ASIO_CONSTEXPR blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::disallowed_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, disallowed_t()); + } + + template + friend ASIO_CONSTEXPR blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::allowed_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, allowed_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const blocking_adaptation_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T blocking_adaptation_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const blocking_adaptation_t blocking_adaptation_t::instance; +#endif + +template +const typename blocking_adaptation_t::disallowed_t +blocking_adaptation_t::disallowed; + +template +const typename blocking_adaptation_t::allowed_t +blocking_adaptation_t::allowed; + +namespace blocking_adaptation { + +template +struct disallowed_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_adaptation_t polymorphic_query_result_type; + + ASIO_CONSTEXPR disallowed_t() + { + } + + template + struct query_member : + traits::query_member< + typename blocking_adaptation_t::template proxy::type, + disallowed_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_adaptation_t::template static_proxy::type, + disallowed_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR disallowed_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return disallowed_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = disallowed_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR blocking_adaptation_t value() + { + return disallowed_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const disallowed_t&, const disallowed_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const disallowed_t&, const disallowed_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T disallowed_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +class adapter +{ +public: + adapter(int, const Executor& e) ASIO_NOEXCEPT + : executor_(e) + { + } + + adapter(const adapter& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + adapter(adapter&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + template + static ASIO_CONSTEXPR allowed_t query( + blocking_adaptation_t) ASIO_NOEXCEPT + { + return allowed_t(); + } + + template + static ASIO_CONSTEXPR allowed_t query( + allowed_t) ASIO_NOEXCEPT + { + return allowed_t(); + } + + template + static ASIO_CONSTEXPR allowed_t query( + disallowed_t) ASIO_NOEXCEPT + { + return allowed_t(); + } + + template + typename enable_if< + can_query::value, + typename query_result::type + >::type query(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) + { + return asio::query(executor_, p); + } + + template + Executor require(disallowed_t) const ASIO_NOEXCEPT + { + return executor_; + } + + template + typename enable_if< + can_require::value, + adapter::type + >::type> + >::type require(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_require::value)) + { + return adapter::type + >::type>(0, asio::require(executor_, p)); + } + + template + typename enable_if< + can_prefer::value, + adapter::type + >::type> + >::type prefer(const Property& p) const + ASIO_NOEXCEPT_IF(( + is_nothrow_prefer::value)) + { + return adapter::type + >::type>(0, asio::prefer(executor_, p)); + } + + template + typename enable_if< + execution::can_execute::value + >::type execute(ASIO_MOVE_ARG(Function) f) const + { + execution::execute(executor_, ASIO_MOVE_CAST(Function)(f)); + } + + friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT + { + return a.executor_ == b.executor_; + } + + friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT + { + return a.executor_ != b.executor_; + } + +private: + Executor executor_; +}; + +template +struct allowed_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_adaptation_t polymorphic_query_result_type; + + ASIO_CONSTEXPR allowed_t() + { + } + + template + struct query_member : + traits::query_member< + typename blocking_adaptation_t::template proxy::type, + allowed_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_adaptation_t::template static_proxy::type, + allowed_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = allowed_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR blocking_adaptation_t value() + { + return allowed_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const allowed_t&, const allowed_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const allowed_t&, const allowed_t&) + { + return false; + } + + template + friend adapter require( + const Executor& e, const allowed_t&, + typename enable_if< + is_executor::value + >::type* = 0) + { + return adapter(0, e); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T allowed_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +class blocking_execute_state +{ +public: + template + blocking_execute_state(ASIO_MOVE_ARG(F) f) + : func_(ASIO_MOVE_CAST(F)(f)), + is_complete_(false) + { + } + + template + void execute_and_wait(ASIO_MOVE_ARG(Executor) ex) + { + handler h = { this }; + execution::execute(ASIO_MOVE_CAST(Executor)(ex), h); + asio::detail::mutex::scoped_lock lock(mutex_); + while (!is_complete_) + event_.wait(lock); + } + + struct cleanup + { + ~cleanup() + { + asio::detail::mutex::scoped_lock lock(state_->mutex_); + state_->is_complete_ = true; + state_->event_.unlock_and_signal_one_for_destruction(lock); + } + + blocking_execute_state* state_; + }; + + struct handler + { + void operator()() + { + cleanup c = { state_ }; + state_->func_(); + } + + blocking_execute_state* state_; + }; + + Function func_; + asio::detail::mutex mutex_; + asio::detail::event event_; + bool is_complete_; +}; + +template +void blocking_execute( + ASIO_MOVE_ARG(Executor) ex, + ASIO_MOVE_ARG(Function) func) +{ + typedef typename decay::type func_t; + blocking_execute_state state(ASIO_MOVE_CAST(Function)(func)); + state.execute_and_wait(ex); +} + +} // namespace blocking_adaptation +} // namespace detail + +typedef detail::blocking_adaptation_t<> blocking_adaptation_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr blocking_adaptation_t blocking_adaptation; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const blocking_adaptation_t& + blocking_adaptation = blocking_adaptation_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query::value)); + + typedef execution::blocking_adaptation_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_adaptation_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_adaptation_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_adaptation_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::blocking_adaptation::disallowed_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_adaptation_t::disallowed_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::blocking_adaptation::allowed_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::blocking_adaptation::allowed_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_adaptation_t::disallowed_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_adaptation_t::allowed_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free_default::type>::value + && execution::is_executor::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef execution::detail::blocking_adaptation::adapter result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template +struct equality_comparable< + execution::detail::blocking_adaptation::adapter > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + execution::detail::blocking_adaptation::adapter, Function> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter, + execution::detail::blocking_adaptation_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter, + execution::detail::blocking_adaptation::allowed_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter, + execution::detail::blocking_adaptation::disallowed_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + execution::detail::blocking_adaptation::adapter, Property, + typename enable_if< + can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + typedef typename query_result::type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + execution::detail::blocking_adaptation::adapter, + execution::detail::blocking_adaptation::disallowed_t > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Executor result_type; +}; + +template +struct require_member< + execution::detail::blocking_adaptation::adapter, Property, + typename enable_if< + can_require::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_require::value)); + typedef execution::detail::blocking_adaptation::adapter::type + >::type> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member< + execution::detail::blocking_adaptation::adapter, Property, + typename enable_if< + can_prefer::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_prefer::value)); + typedef execution::detail::blocking_adaptation::adapter::type + >::type> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/bulk_execute.hpp b/extern/asio-1.18.2/include/asio/execution/bulk_execute.hpp new file mode 100644 index 0000000..ef76e06 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/bulk_execute.hpp @@ -0,0 +1,395 @@ +// +// execution/bulk_execute.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_BULK_EXECUTE_HPP +#define ASIO_EXECUTION_BULK_EXECUTE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/bulk_guarantee.hpp" +#include "asio/execution/detail/bulk_sender.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/sender.hpp" +#include "asio/traits/bulk_execute_member.hpp" +#include "asio/traits/bulk_execute_free.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { +namespace execution { + +/// A customisation point that creates a bulk sender. +/** + * The name execution::bulk_execute denotes a customisation point + * object. If is_convertible_v is true, then the expression + * execution::bulk_execute(S, F, N) for some subexpressions + * S, F, and N is expression-equivalent to: + * + * @li S.bulk_execute(F, N), if that expression is valid. If the + * function selected does not execute N invocations of the function + * object F on the executor S in bulk with forward progress + * guarantee asio::query(S, execution::bulk_guarantee), and + * the result of that function does not model sender, the + * program is ill-formed with no diagnostic required. + * + * @li Otherwise, bulk_execute(S, F, N), if that expression is valid, + * with overload resolution performed in a context that includes the + * declaration void bulk_execute(); and that does not include a + * declaration of execution::bulk_execute. If the function selected + * by overload resolution does not execute N invocations of the + * function object F on the executor S in bulk with forward + * progress guarantee asio::query(E, + * execution::bulk_guarantee), and the result of that function does not + * model sender, the program is ill-formed with no diagnostic + * required. + * + * @li Otherwise, if the types F and + * executor_index_t> model invocable and + * if asio::query(S, execution::bulk_guarantee) equals + * execution::bulk_guarantee.unsequenced, then + * + * - Evaluates DECAY_COPY(std::forward(F)) on the + * calling thread to create a function object cf. [Note: + * Additional copies of cf may subsequently be created. --end + * note.] + * + * - For each value of i in N, cf(i) (or copy of + * cf)) will be invoked at most once by an execution agent that is + * unique for each value of i. + * + * - May block pending completion of one or more invocations of cf. + * + * - Synchronizes with (C++Std [intro.multithread]) the invocations of + * cf. + * + * @li Otherwise, execution::bulk_execute(S, F, N) is ill-formed. + */ +inline constexpr unspecified bulk_execute = unspecified; + +/// A type trait that determines whether a @c bulk_execute expression is +/// well-formed. +/** + * Class template @c can_bulk_execute is a trait that is derived from @c + * true_type if the expression execution::bulk_execute(std::declval(), + * std::declval(), std::declval) is well formed; otherwise @c + * false_type. + */ +template +struct can_bulk_execute : + integral_constant +{ +}; + +} // namespace execution +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_execution_bulk_execute_fn { + +using asio::declval; +using asio::enable_if; +using asio::execution::bulk_guarantee_t; +using asio::execution::detail::bulk_sender; +using asio::execution::executor_index; +using asio::execution::is_sender; +using asio::is_convertible; +using asio::is_same; +using asio::remove_cvref; +using asio::result_of; +using asio::traits::bulk_execute_free; +using asio::traits::bulk_execute_member; +using asio::traits::static_require; + +void bulk_execute(); + +enum overload_type +{ + call_member, + call_free, + adapter, + ill_formed +}; + +template +struct call_traits +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::value + >::type, + typename enable_if< + bulk_execute_member::is_valid + >::type, + typename enable_if< + is_sender< + typename bulk_execute_member::result_type + >::value + >::type> : + bulk_execute_member +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::value + >::type, + typename enable_if< + !bulk_execute_member::is_valid + >::type, + typename enable_if< + bulk_execute_free::is_valid + >::type, + typename enable_if< + is_sender< + typename bulk_execute_free::result_type + >::value + >::type> : + bulk_execute_free +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +template +struct call_traits::value + >::type, + typename enable_if< + !bulk_execute_member::is_valid + >::type, + typename enable_if< + !bulk_execute_free::is_valid + >::type, + typename enable_if< + is_sender::value + >::type, + typename enable_if< + is_same< + typename result_of< + F(typename executor_index::type>::type) + >::type, + typename result_of< + F(typename executor_index::type>::type) + >::type + >::value + >::type, + typename enable_if< + static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef bulk_sender result_type; +}; + +struct impl +{ +#if defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S&& s, F&& f, N&& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return ASIO_MOVE_CAST(S)(s).bulk_execute( + ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S&& s, F&& f, N&& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return bulk_execute(ASIO_MOVE_CAST(S)(s), + ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(S&& s, F&& f, N&& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type( + ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(F)(f), + ASIO_MOVE_CAST(N)(n)); + } +#else // defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.bulk_execute(ASIO_MOVE_CAST(F)(f), + ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(const S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.bulk_execute(ASIO_MOVE_CAST(F)(f), + ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return bulk_execute(s, ASIO_MOVE_CAST(F)(f), + ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(const S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return bulk_execute(s, ASIO_MOVE_CAST(F)(f), + ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type( + s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(const S& s, const F& f, const N& n) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type( + s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n)); + } +#endif // defined(ASIO_HAS_MOVE) +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_execution_bulk_execute_fn +namespace asio { +namespace execution { +namespace { + +static ASIO_CONSTEXPR + const asio_execution_bulk_execute_fn::impl& bulk_execute = + asio_execution_bulk_execute_fn::static_instance<>::instance; + +} // namespace + +template +struct can_bulk_execute : + integral_constant::overload != + asio_execution_bulk_execute_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_bulk_execute_v = can_bulk_execute::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_nothrow_bulk_execute : + integral_constant::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_bulk_execute_v + = is_nothrow_bulk_execute::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct bulk_execute_result +{ + typedef typename asio_execution_bulk_execute_fn::call_traits< + S, void(F, N)>::result_type type; +}; + +} // namespace execution +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BULK_EXECUTE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/bulk_guarantee.hpp b/extern/asio-1.18.2/include/asio/execution/bulk_guarantee.hpp new file mode 100644 index 0000000..6482218 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/bulk_guarantee.hpp @@ -0,0 +1,1215 @@ +// +// execution/bulk_guarantee.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_BULK_GUARANTEE_HPP +#define ASIO_EXECUTION_BULK_GUARANTEE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to communicate the forward progress and ordering guarantees of +/// execution agents associated with the bulk execution. +struct bulk_guarantee_t +{ + /// The bulk_guarantee_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level bulk_guarantee_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level bulk_guarantee_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may be parallelised and vectorised. + struct unsequenced_t + { + /// The bulk_guarantee_t::unsequenced_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The bulk_guarantee_t::unsequenced_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::unsequenced_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr unsequenced_t(); + + /// Get the value associated with a property object. + /** + * @returns unsequenced_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may not be parallelised and vectorised. + struct sequenced_t + { + /// The bulk_guarantee_t::sequenced_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The bulk_guarantee_t::sequenced_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::sequenced_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr sequenced_t(); + + /// Get the value associated with a property object. + /** + * @returns sequenced_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may be parallelised. + struct parallel_t + { + /// The bulk_guarantee_t::parallel_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The bulk_guarantee_t::parallel_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::parallel_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr parallel_t(); + + /// Get the value associated with a property object. + /** + * @returns parallel_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A special value used for accessing the bulk_guarantee_t::unsequenced_t + /// property. + static constexpr unsequenced_t unsequenced; + + /// A special value used for accessing the bulk_guarantee_t::sequenced_t + /// property. + static constexpr sequenced_t sequenced; + + /// A special value used for accessing the bulk_guarantee_t::parallel_t + /// property. + static constexpr parallel_t parallel; + + /// Default constructor. + constexpr bulk_guarantee_t(); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(unsequenced_t); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(sequenced_t); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(parallel_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; +}; + +/// A special value used for accessing the bulk_guarantee_t property. +constexpr bulk_guarantee_t bulk_guarantee; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace bulk_guarantee { + +template struct unsequenced_t; +template struct sequenced_t; +template struct parallel_t; + +} // namespace bulk_guarantee + +template +struct bulk_guarantee_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef bulk_guarantee_t polymorphic_query_result_type; + + typedef detail::bulk_guarantee::unsequenced_t unsequenced_t; + typedef detail::bulk_guarantee::sequenced_t sequenced_t; + typedef detail::bulk_guarantee::parallel_t parallel_t; + + ASIO_CONSTEXPR bulk_guarantee_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR bulk_guarantee_t(unsequenced_t) + : value_(0) + { + } + + ASIO_CONSTEXPR bulk_guarantee_t(sequenced_t) + : value_(1) + { + } + + ASIO_CONSTEXPR bulk_guarantee_t(parallel_t) + : value_(2) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, bulk_guarantee_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, bulk_guarantee_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = bulk_guarantee_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_bulk_guarantee_t + { + ASIO_CONSTEXPR convertible_from_bulk_guarantee_t(bulk_guarantee_t) {} + }; + + template + friend ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::unsequenced_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, unsequenced_t()); + } + + template + friend ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::sequenced_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, sequenced_t()); + } + + template + friend ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::parallel_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, parallel_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(unsequenced_t, unsequenced); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(sequenced_t, sequenced); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(parallel_t, parallel); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const bulk_guarantee_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T bulk_guarantee_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const bulk_guarantee_t bulk_guarantee_t::instance; +#endif + +template +const typename bulk_guarantee_t::unsequenced_t +bulk_guarantee_t::unsequenced; + +template +const typename bulk_guarantee_t::sequenced_t +bulk_guarantee_t::sequenced; + +template +const typename bulk_guarantee_t::parallel_t +bulk_guarantee_t::parallel; + +namespace bulk_guarantee { + +template +struct unsequenced_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + ASIO_CONSTEXPR unsequenced_t() + { + } + + template + struct query_member : + traits::query_member< + typename bulk_guarantee_t::template proxy::type, + unsequenced_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename bulk_guarantee_t::template static_proxy::type, + unsequenced_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR unsequenced_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return unsequenced_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = unsequenced_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR bulk_guarantee_t value() + { + return unsequenced_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const unsequenced_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const unsequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const sequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const sequenced_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const parallel_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const parallel_t&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T unsequenced_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct sequenced_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + ASIO_CONSTEXPR sequenced_t() + { + } + + template + struct query_member : + traits::query_member< + typename bulk_guarantee_t::template proxy::type, + sequenced_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename bulk_guarantee_t::template static_proxy::type, + sequenced_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = sequenced_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR bulk_guarantee_t value() + { + return sequenced_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const sequenced_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const sequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const unsequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const unsequenced_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const parallel_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const parallel_t&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T sequenced_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct parallel_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + ASIO_CONSTEXPR parallel_t() + { + } + + template + struct query_member : + traits::query_member< + typename bulk_guarantee_t::template proxy::type, + parallel_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename bulk_guarantee_t::template static_proxy::type, + parallel_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = parallel_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR bulk_guarantee_t value() + { + return parallel_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const parallel_t&, const parallel_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const parallel_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator==( + const parallel_t&, const unsequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const unsequenced_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator==( + const parallel_t&, const sequenced_t&) + { + return false; + } + + friend ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const sequenced_t&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T parallel_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace bulk_guarantee +} // namespace detail + +typedef detail::bulk_guarantee_t<> bulk_guarantee_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr bulk_guarantee_t bulk_guarantee; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const bulk_guarantee_t& + bulk_guarantee = bulk_guarantee_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::bulk_guarantee_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::bulk_guarantee_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::bulk_guarantee_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::bulk_guarantee_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::bulk_guarantee_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::bulk_guarantee::unsequenced_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::bulk_guarantee::unsequenced_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::bulk_guarantee::unsequenced_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::bulk_guarantee_t::unsequenced_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::bulk_guarantee::sequenced_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::bulk_guarantee::sequenced_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::bulk_guarantee::parallel_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::bulk_guarantee::parallel_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::unsequenced_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::sequenced_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::parallel_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BULK_GUARANTEE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/connect.hpp b/extern/asio-1.18.2/include/asio/execution/connect.hpp new file mode 100644 index 0000000..527f123 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/connect.hpp @@ -0,0 +1,489 @@ +// +// execution/connect.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_CONNECT_HPP +#define ASIO_EXECUTION_CONNECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/detail/as_invocable.hpp" +#include "asio/execution/detail/as_operation.hpp" +#include "asio/execution/detail/as_receiver.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/operation_state.hpp" +#include "asio/execution/receiver.hpp" +#include "asio/execution/sender.hpp" +#include "asio/traits/connect_member.hpp" +#include "asio/traits/connect_free.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { +namespace execution { + +/// A customisation point that connects a sender to a receiver. +/** + * The name execution::connect denotes a customisation point object. + * For some subexpressions s and r, let S be a type + * such that decltype((s)) is S and let R be a type + * such that decltype((r)) is R. The expression + * execution::connect(s, r) is expression-equivalent to: + * + * @li s.connect(r), if that expression is valid, if its type + * satisfies operation_state, and if S satisfies + * sender. + * + * @li Otherwise, connect(s, r), if that expression is valid, if its + * type satisfies operation_state, and if S satisfies + * sender, with overload resolution performed in a context that + * includes the declaration void connect(); and that does not include + * a declaration of execution::connect. + * + * @li Otherwise, as_operation{s, r}, if r is not an instance + * of as_receiver for some type F, and if + * receiver_of && executor_of, + * as_invocable, S>> is true, where + * as_operation is an implementation-defined class equivalent to + * @code template + * struct as_operation + * { + * remove_cvref_t e_; + * remove_cvref_t r_; + * void start() noexcept try { + * execution::execute(std::move(e_), + * as_invocable, S>{r_}); + * } catch(...) { + * execution::set_error(std::move(r_), current_exception()); + * } + * }; @endcode + * and as_invocable is a class template equivalent to the following: + * @code template + * struct as_invocable + * { + * R* r_; + * explicit as_invocable(R& r) noexcept + * : r_(std::addressof(r)) {} + * as_invocable(as_invocable && other) noexcept + * : r_(std::exchange(other.r_, nullptr)) {} + * ~as_invocable() { + * if(r_) + * execution::set_done(std::move(*r_)); + * } + * void operator()() & noexcept try { + * execution::set_value(std::move(*r_)); + * r_ = nullptr; + * } catch(...) { + * execution::set_error(std::move(*r_), current_exception()); + * r_ = nullptr; + * } + * }; + * @endcode + * + * @li Otherwise, execution::connect(s, r) is ill-formed. + */ +inline constexpr unspecified connect = unspecified; + +/// A type trait that determines whether a @c connect expression is +/// well-formed. +/** + * Class template @c can_connect is a trait that is derived from + * @c true_type if the expression execution::connect(std::declval(), + * std::declval()) is well formed; otherwise @c false_type. + */ +template +struct can_connect : + integral_constant +{ +}; + +/// A type trait to determine the result of a @c connect expression. +template +struct connect_result +{ + /// The type of the connect expression. + /** + * The type of the expression execution::connect(std::declval(), + * std::declval()). + */ + typedef automatically_determined type; +}; + +/// A type alis to determine the result of a @c connect expression. +template +using connect_result_t = typename connect_result::type; + +} // namespace execution +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_execution_connect_fn { + +using asio::conditional; +using asio::declval; +using asio::enable_if; +using asio::execution::detail::as_invocable; +using asio::execution::detail::as_operation; +using asio::execution::detail::is_as_receiver; +using asio::execution::is_executor_of; +using asio::execution::is_operation_state; +using asio::execution::is_receiver; +using asio::execution::is_sender; +using asio::false_type; +using asio::remove_cvref; +using asio::traits::connect_free; +using asio::traits::connect_member; + +void connect(); + +enum overload_type +{ + call_member, + call_free, + adapter, + ill_formed +}; + +template +struct call_traits +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::is_valid + >::type, + typename enable_if< + is_operation_state::result_type>::value + >::type, + typename enable_if< + is_sender::type>::value + >::type> : + connect_member +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::is_valid + >::type, + typename enable_if< + connect_free::is_valid + >::type, + typename enable_if< + is_operation_state::result_type>::value + >::type, + typename enable_if< + is_sender::type>::value + >::type> : + connect_free +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +template +struct call_traits::is_valid + >::type, + typename enable_if< + !connect_free::is_valid + >::type, + typename enable_if< + is_receiver::value + >::type, + typename enable_if< + conditional< + !is_as_receiver< + typename remove_cvref::type + >::value, + is_executor_of< + typename remove_cvref::type, + as_invocable::type, S> + >, + false_type + >::type::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef as_operation result_type; +}; + +struct impl +{ +#if defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S&& s, R&& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return ASIO_MOVE_CAST(S)(s).connect(ASIO_MOVE_CAST(R)(r)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S&& s, R&& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return connect(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(S&& s, R&& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type( + ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r)); + } +#else // defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.connect(r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(const S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.connect(r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return connect(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(const S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return connect(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(const S& s, R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.connect(r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(const S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.connect(r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return connect(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(const S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return connect(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type(s, r); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()(const S& s, const R& r) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return typename call_traits::result_type(s, r); + } +#endif // defined(ASIO_HAS_MOVE) +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_execution_connect_fn +namespace asio { +namespace execution { +namespace { + +static ASIO_CONSTEXPR const asio_execution_connect_fn::impl& + connect = asio_execution_connect_fn::static_instance<>::instance; + +} // namespace + +template +struct can_connect : + integral_constant::overload != + asio_execution_connect_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_connect_v = can_connect::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_nothrow_connect : + integral_constant::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_connect_v + = is_nothrow_connect::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct connect_result +{ + typedef typename asio_execution_connect_fn::call_traits< + S, void(R)>::result_type type; +}; + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template +using connect_result_t = typename connect_result::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace execution +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_CONNECT_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/context.hpp b/extern/asio-1.18.2/include/asio/execution/context.hpp new file mode 100644 index 0000000..f751c7a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/context.hpp @@ -0,0 +1,233 @@ +// +// execution/context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_CONTEXT2_HPP +#define ASIO_EXECUTION_CONTEXT2_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#if defined(ASIO_HAS_STD_ANY) +# include +#endif // defined(ASIO_HAS_STD_ANY) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +struct context_t +{ + /// The context_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef std::any polymorphic_query_result_type; +}; + +/// A special value used for accessing the context_t property. +constexpr context_t context; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct context_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + +#if defined(ASIO_HAS_STD_ANY) + typedef std::any polymorphic_query_result_type; +#endif // defined(ASIO_HAS_STD_ANY) + + ASIO_CONSTEXPR context_t() + { + } + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, context_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = context_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) + static const context_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T context_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const context_t context_t::instance; +#endif + +} // namespace detail + +typedef detail::context_t<> context_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr context_t context; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const context_t& context = context_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::context_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::context_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_CONTEXT2_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/context_as.hpp b/extern/asio-1.18.2/include/asio/execution/context_as.hpp new file mode 100644 index 0000000..740918c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/context_as.hpp @@ -0,0 +1,221 @@ +// +// execution/context_as.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_CONTEXT_AS_HPP +#define ASIO_EXECUTION_CONTEXT_AS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +template +struct context_as_t +{ + /// The context_as_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef T polymorphic_query_result_type; +}; + +/// A special value used for accessing the context_as_t property. +template +constexpr context_as_t context_as; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template +struct context_as_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + + typedef T polymorphic_query_result_type; + + ASIO_CONSTEXPR context_as_t() + { + } + + ASIO_CONSTEXPR context_as_t(context_t) + { + } + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename context_t::query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + context_t::query_static_constexpr_member::is_noexcept)) + { + return context_t::query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const U static_query_v + = context_as_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + friend ASIO_CONSTEXPR U query( + const Executor& ex, const context_as_t&, + typename enable_if< + is_same::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, context); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const U context_as_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if (defined(ASIO_HAS_VARIABLE_TEMPLATES) \ + && defined(ASIO_HAS_CONSTEXPR)) \ + || defined(GENERATING_DOCUMENTATION) +template +constexpr context_as_t context_as{}; +#endif // (defined(ASIO_HAS_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_CONSTEXPR)) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property > + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query, + typename enable_if< + static_query::is_valid + >::type> : static_query +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free, + typename enable_if< + can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef U result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_CONTEXT_AS_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/as_invocable.hpp b/extern/asio-1.18.2/include/asio/execution/detail/as_invocable.hpp new file mode 100644 index 0000000..13b6e44 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/as_invocable.hpp @@ -0,0 +1,152 @@ +// +// execution/detail/as_invocable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP +#define ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/receiver_invocation_error.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/execution/set_value.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +#if defined(ASIO_HAS_MOVE) + +template +struct as_invocable +{ + Receiver* receiver_; + + explicit as_invocable(Receiver& r) ASIO_NOEXCEPT + : receiver_(asio::detail::addressof(r)) + { + } + + as_invocable(as_invocable&& other) ASIO_NOEXCEPT + : receiver_(other.receiver_) + { + other.receiver_ = 0; + } + + ~as_invocable() + { + if (receiver_) + execution::set_done(ASIO_MOVE_OR_LVALUE(Receiver)(*receiver_)); + } + + void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT + { +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + execution::set_value(ASIO_MOVE_CAST(Receiver)(*receiver_)); + receiver_ = 0; +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) + execution::set_error(ASIO_MOVE_CAST(Receiver)(*receiver_), + std::make_exception_ptr(receiver_invocation_error())); + receiver_ = 0; +#else // defined(ASIO_HAS_STD_EXCEPTION_PTR) + std::terminate(); +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } +}; + +#else // defined(ASIO_HAS_MOVE) + +template +struct as_invocable +{ + Receiver* receiver_; + asio::detail::shared_ptr ref_count_; + + explicit as_invocable(Receiver& r, + const asio::detail::shared_ptr< + asio::detail::atomic_count>& c) ASIO_NOEXCEPT + : receiver_(asio::detail::addressof(r)), + ref_count_(c) + { + } + + as_invocable(const as_invocable& other) ASIO_NOEXCEPT + : receiver_(other.receiver_), + ref_count_(other.ref_count_) + { + ++(*ref_count_); + } + + ~as_invocable() + { + if (--(*ref_count_) == 0) + execution::set_done(*receiver_); + } + + void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT + { +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + execution::set_value(*receiver_); + ++(*ref_count_); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (...) + { +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) + execution::set_error(*receiver_, + std::make_exception_ptr(receiver_invocation_error())); + ++(*ref_count_); +#else // defined(ASIO_HAS_STD_EXCEPTION_PTR) + std::terminate(); +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } +}; + +#endif // defined(ASIO_HAS_MOVE) + +template +struct is_as_invocable : false_type +{ +}; + +template +struct is_as_invocable > : true_type +{ +}; + +} // namespace detail +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/as_operation.hpp b/extern/asio-1.18.2/include/asio/execution/detail/as_operation.hpp new file mode 100644 index 0000000..565bf36 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/as_operation.hpp @@ -0,0 +1,105 @@ +// +// execution/detail/as_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP +#define ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/detail/as_invocable.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/traits/start_member.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct as_operation +{ + typename remove_cvref::type ex_; + typename remove_cvref::type receiver_; +#if !defined(ASIO_HAS_MOVE) + asio::detail::shared_ptr ref_count_; +#endif // !defined(ASIO_HAS_MOVE) + + template + explicit as_operation(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(R) r) + : ex_(ASIO_MOVE_CAST(E)(e)), + receiver_(ASIO_MOVE_CAST(R)(r)) +#if !defined(ASIO_HAS_MOVE) + , ref_count_(new asio::detail::atomic_count(1)) +#endif // !defined(ASIO_HAS_MOVE) + { + } + + void start() ASIO_NOEXCEPT + { +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + execution::execute( + ASIO_MOVE_CAST(typename remove_cvref::type)(ex_), + as_invocable::type, + Executor>(receiver_ +#if !defined(ASIO_HAS_MOVE) + , ref_count_ +#endif // !defined(ASIO_HAS_MOVE) + )); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) + execution::set_error( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)( + receiver_), + std::current_exception()); +#else // defined(ASIO_HAS_STD_EXCEPTION_PTR) + std::terminate(); +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } +}; + +} // namespace detail +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) + +template +struct start_member< + asio::execution::detail::as_operation > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/as_receiver.hpp b/extern/asio-1.18.2/include/asio/execution/detail/as_receiver.hpp new file mode 100644 index 0000000..a10bdc7 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/as_receiver.hpp @@ -0,0 +1,128 @@ +// +// execution/detail/as_receiver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP +#define ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/traits/set_done_member.hpp" +#include "asio/traits/set_error_member.hpp" +#include "asio/traits/set_value_member.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct as_receiver +{ + Function f_; + + template + explicit as_receiver(ASIO_MOVE_ARG(F) f, int) + : f_(ASIO_MOVE_CAST(F)(f)) + { + } + +#if defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE) + as_receiver(as_receiver&& other) + : f_(ASIO_MOVE_CAST(Function)(other.f_)) + { + } +#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE) + + void set_value() + ASIO_NOEXCEPT_IF(noexcept(declval()())) + { + f_(); + } + + template + void set_error(E) ASIO_NOEXCEPT + { + std::terminate(); + } + + void set_done() ASIO_NOEXCEPT + { + } +}; + +template +struct is_as_receiver : false_type +{ +}; + +template +struct is_as_receiver > : true_type +{ +}; + +} // namespace detail +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +template +struct set_value_member< + asio::execution::detail::as_receiver, void()> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); +#if defined(ASIO_HAS_NOEXCEPT) + ASIO_STATIC_CONSTEXPR(bool, + is_noexcept = noexcept(declval()())); +#else // defined(ASIO_HAS_NOEXCEPT) + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); +#endif // defined(ASIO_HAS_NOEXCEPT) + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +template +struct set_error_member< + asio::execution::detail::as_receiver, E> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +template +struct set_done_member< + asio::execution::detail::as_receiver > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/bulk_sender.hpp b/extern/asio-1.18.2/include/asio/execution/detail/bulk_sender.hpp new file mode 100644 index 0000000..0e4e5c1 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/bulk_sender.hpp @@ -0,0 +1,261 @@ +// +// execution/detail/bulk_sender.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP +#define ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/connect.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/traits/connect_member.hpp" +#include "asio/traits/set_done_member.hpp" +#include "asio/traits/set_error_member.hpp" +#include "asio/traits/set_value_member.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct bulk_receiver +{ + typename remove_cvref::type receiver_; + typename decay::type f_; + typename decay::type n_; + + template + explicit bulk_receiver(ASIO_MOVE_ARG(R) r, + ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n) + : receiver_(ASIO_MOVE_CAST(R)(r)), + f_(ASIO_MOVE_CAST(F)(f)), + n_(ASIO_MOVE_CAST(N)(n)) + { + } + + void set_value() + { + for (Index i = 0; i < n_; ++i) + f_(i); + + execution::set_value( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(receiver_)); + } + + template + void set_error(ASIO_MOVE_ARG(Error) e) ASIO_NOEXCEPT + { + execution::set_error( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(receiver_), + ASIO_MOVE_CAST(Error)(e)); + } + + void set_done() ASIO_NOEXCEPT + { + execution::set_done( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(receiver_)); + } +}; + +template +struct bulk_receiver_traits +{ + typedef bulk_receiver< + Receiver, Function, Number, + typename execution::executor_index< + typename remove_cvref::type + >::type + > type; + +#if defined(ASIO_HAS_MOVE) + typedef type arg_type; +#else // defined(ASIO_HAS_MOVE) + typedef const type& arg_type; +#endif // defined(ASIO_HAS_MOVE) +}; + +template +struct bulk_sender : sender_base +{ + typename remove_cvref::type sender_; + typename decay::type f_; + typename decay::type n_; + + template + explicit bulk_sender(ASIO_MOVE_ARG(S) s, + ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n) + : sender_(ASIO_MOVE_CAST(S)(s)), + f_(ASIO_MOVE_CAST(F)(f)), + n_(ASIO_MOVE_CAST(N)(n)) + { + } + + template + typename connect_result< + ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref::type), + typename bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::type connect(ASIO_MOVE_ARG(Receiver) r, + typename enable_if< + can_connect< + typename remove_cvref::type, + typename bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::value + >::type* = 0) ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT + { + return execution::connect( + ASIO_MOVE_OR_LVALUE(typename remove_cvref::type)(sender_), + typename bulk_receiver_traits::type( + ASIO_MOVE_CAST(Receiver)(r), + ASIO_MOVE_CAST(typename decay::type)(f_), + ASIO_MOVE_CAST(typename decay::type)(n_))); + } + + template + typename connect_result< + const typename remove_cvref::type&, + typename bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::type connect(ASIO_MOVE_ARG(Receiver) r, + typename enable_if< + can_connect< + const typename remove_cvref::type&, + typename bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::value + >::type* = 0) const ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT + { + return execution::connect(sender_, + typename bulk_receiver_traits::type( + ASIO_MOVE_CAST(Receiver)(r), f_, n_)); + } +}; + +} // namespace detail +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +template +struct set_value_member< + execution::detail::bulk_receiver, + void()> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +template +struct set_error_member< + execution::detail::bulk_receiver, + Error> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +template +struct set_done_member< + execution::detail::bulk_receiver > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) + +template +struct connect_member< + execution::detail::bulk_sender, + Receiver, + typename enable_if< + execution::can_connect< + ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref::type), + typename execution::detail::bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef typename execution::connect_result< + ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref::type), + typename execution::detail::bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::type result_type; +}; + +template +struct connect_member< + const execution::detail::bulk_sender, + Receiver, + typename enable_if< + execution::can_connect< + const typename remove_cvref::type&, + typename execution::detail::bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef typename execution::connect_result< + const typename remove_cvref::type&, + typename execution::detail::bulk_receiver_traits< + Sender, Receiver, Function, Number + >::arg_type + >::type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/submit_receiver.hpp b/extern/asio-1.18.2/include/asio/execution/detail/submit_receiver.hpp new file mode 100644 index 0000000..6faa119 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/submit_receiver.hpp @@ -0,0 +1,233 @@ +// +// execution/detail/submit_receiver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP +#define ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/execution/connect.hpp" +#include "asio/execution/receiver.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/execution/set_value.hpp" +#include "asio/traits/set_done_member.hpp" +#include "asio/traits/set_error_member.hpp" +#include "asio/traits/set_value_member.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct submit_receiver; + +template +struct submit_receiver_wrapper +{ + submit_receiver* p_; + + explicit submit_receiver_wrapper(submit_receiver* p) + : p_(p) + { + } + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + typename enable_if::value>::type + set_value(ASIO_MOVE_ARG(Args)... args) ASIO_RVALUE_REF_QUAL + ASIO_NOEXCEPT_IF((is_nothrow_receiver_of::value)) + { + execution::set_value( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(p_->r_), + ASIO_MOVE_CAST(Args)(args)...); + delete p_; + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + void set_value() ASIO_RVALUE_REF_QUAL + ASIO_NOEXCEPT_IF((is_nothrow_receiver_of::value)) + { + execution::set_value( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(p_->r_)); + delete p_; + } + +#define ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF(n) \ + template \ + typename enable_if::value>::type \ + set_value(ASIO_VARIADIC_MOVE_PARAMS(n)) ASIO_RVALUE_REF_QUAL \ + ASIO_NOEXCEPT_IF((is_nothrow_receiver_of< \ + Receiver, ASIO_VARIADIC_TARGS(n)>::value)) \ + { \ + execution::set_value( \ + ASIO_MOVE_OR_LVALUE( \ + typename remove_cvref::type)(p_->r_), \ + ASIO_VARIADIC_MOVE_ARGS(n)); \ + delete p_; \ + } \ + /**/ +ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF) +#undef ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template + void set_error(ASIO_MOVE_ARG(E) e) + ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT + { + execution::set_error( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(p_->r_), + ASIO_MOVE_CAST(E)(e)); + delete p_; + } + + void set_done() ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT + { + execution::set_done( + ASIO_MOVE_OR_LVALUE( + typename remove_cvref::type)(p_->r_)); + delete p_; + } +}; + +template +struct submit_receiver +{ + typename remove_cvref::type r_; +#if defined(ASIO_HAS_MOVE) + typename connect_result >::type state_; +#else // defined(ASIO_HAS_MOVE) + typename connect_result& >::type state_; +#endif // defined(ASIO_HAS_MOVE) + +#if defined(ASIO_HAS_MOVE) + template + explicit submit_receiver(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r) + : r_(ASIO_MOVE_CAST(R)(r)), + state_(execution::connect(ASIO_MOVE_CAST(S)(s), + submit_receiver_wrapper(this))) + { + } +#else // defined(ASIO_HAS_MOVE) + explicit submit_receiver(Sender s, Receiver r) + : r_(r), + state_(execution::connect(s, + submit_receiver_wrapper(this))) + { + } +#endif // defined(ASIO_HAS_MOVE) +}; + +} // namespace detail +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct set_value_member< + asio::execution::detail::submit_receiver_wrapper< + Sender, Receiver>, + void(Args...)> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (asio::execution::is_nothrow_receiver_of::value)); + typedef void result_type; +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct set_value_member< + asio::execution::detail::submit_receiver_wrapper< + Sender, Receiver>, + void()> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + asio::execution::is_nothrow_receiver_of::value); + typedef void result_type; +}; + +#define ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF(n) \ + template \ + struct set_value_member< \ + asio::execution::detail::submit_receiver_wrapper< \ + Sender, Receiver>, \ + void(ASIO_VARIADIC_TARGS(n))> \ + { \ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \ + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = \ + (asio::execution::is_nothrow_receiver_of::value)); \ + typedef void result_type; \ + }; \ + /**/ +ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF) +#undef ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +template +struct set_error_member< + asio::execution::detail::submit_receiver_wrapper< + Sender, Receiver>, E> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +template +struct set_done_member< + asio::execution::detail::submit_receiver_wrapper< + Sender, Receiver> > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/detail/void_receiver.hpp b/extern/asio-1.18.2/include/asio/execution/detail/void_receiver.hpp new file mode 100644 index 0000000..fb2d53f --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/detail/void_receiver.hpp @@ -0,0 +1,90 @@ +// +// execution/detail/void_receiver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP +#define ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/traits/set_done_member.hpp" +#include "asio/traits/set_error_member.hpp" +#include "asio/traits/set_value_member.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +struct void_receiver +{ + void set_value() ASIO_NOEXCEPT + { + } + + template + void set_error(ASIO_MOVE_ARG(E)) ASIO_NOEXCEPT + { + } + + void set_done() ASIO_NOEXCEPT + { + } +}; + +} // namespace detail +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +template <> +struct set_value_member +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +template +struct set_error_member +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +template <> +struct set_done_member +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/execute.hpp b/extern/asio-1.18.2/include/asio/execution/execute.hpp new file mode 100644 index 0000000..54eb31b --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/execute.hpp @@ -0,0 +1,283 @@ +// +// execution/execute.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_EXECUTE_HPP +#define ASIO_EXECUTION_EXECUTE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/detail/as_invocable.hpp" +#include "asio/execution/detail/as_receiver.hpp" +#include "asio/traits/execute_member.hpp" +#include "asio/traits/execute_free.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { +namespace execution { + +/// A customisation point that executes a function on an executor. +/** + * The name execution::execute denotes a customisation point object. + * + * For some subexpressions e and f, let E be a type + * such that decltype((e)) is E and let F be a type + * such that decltype((f)) is F. The expression + * execution::execute(e, f) is ill-formed if F does not model + * invocable, or if E does not model either executor + * or sender. Otherwise, it is expression-equivalent to: + * + * @li e.execute(f), if that expression is valid. If the function + * selected does not execute the function object f on the executor + * e, the program is ill-formed with no diagnostic required. + * + * @li Otherwise, execute(e, f), if that expression is valid, with + * overload resolution performed in a context that includes the declaration + * void execute(); and that does not include a declaration of + * execution::execute. If the function selected by overload + * resolution does not execute the function object f on the executor + * e, the program is ill-formed with no diagnostic required. + */ +inline constexpr unspecified execute = unspecified; + +/// A type trait that determines whether a @c execute expression is well-formed. +/** + * Class template @c can_execute is a trait that is derived from + * @c true_type if the expression execution::execute(std::declval(), + * std::declval()) is well formed; otherwise @c false_type. + */ +template +struct can_execute : + integral_constant +{ +}; + +} // namespace execution +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio { +namespace execution { + +template +struct is_sender_to; + +namespace detail { + +template +void submit_helper(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r); + +} // namespace detail +} // namespace execution +} // namespace asio +namespace asio_execution_execute_fn { + +using asio::conditional; +using asio::decay; +using asio::declval; +using asio::enable_if; +using asio::execution::detail::as_receiver; +using asio::execution::detail::is_as_invocable; +using asio::execution::is_sender_to; +using asio::false_type; +using asio::result_of; +using asio::traits::execute_free; +using asio::traits::execute_member; +using asio::true_type; +using asio::void_type; + +void execute(); + +enum overload_type +{ + call_member, + call_free, + adapter, + ill_formed +}; + +template +struct call_traits +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); +}; + +template +struct call_traits::type, F>::is_valid + >::type> : + execute_member::type, F> +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits, F>::is_valid + >::type, + typename enable_if< + execute_free::is_valid + >::type> : + execute_free +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +template +struct call_traits::type, F>::is_valid + >::type, + typename enable_if< + !execute_free::is_valid + >::type, + typename void_type< + typename result_of::type&()>::type + >::type, + typename enable_if< + !is_as_invocable::type>::value + >::type, + typename enable_if< + is_sender_to::type, T> >::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +struct impl +{ + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + struct type + { + template + auto execute(ASIO_MOVE_ARG(F) f) + noexcept( + noexcept( + declval::type>().execute( + ASIO_MOVE_CAST(F)(f)) + ) + ) + -> decltype( + declval::type>().execute( + ASIO_MOVE_CAST(F)(f)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + }; + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()( + ASIO_MOVE_ARG(T) t, + ASIO_MOVE_ARG(F) f) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return ASIO_MOVE_CAST(T)(t).execute(ASIO_MOVE_CAST(F)(f)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()( + ASIO_MOVE_ARG(T) t, + ASIO_MOVE_ARG(F) f) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return execute(ASIO_MOVE_CAST(T)(t), ASIO_MOVE_CAST(F)(f)); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == adapter, + typename call_traits::result_type + >::type + operator()( + ASIO_MOVE_ARG(T) t, + ASIO_MOVE_ARG(F) f) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return asio::execution::detail::submit_helper( + ASIO_MOVE_CAST(T)(t), + as_receiver::type, T>( + ASIO_MOVE_CAST(F)(f), 0)); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_execution_execute_fn +namespace asio { +namespace execution { +namespace { + +static ASIO_CONSTEXPR const asio_execution_execute_fn::impl& + execute = asio_execution_execute_fn::static_instance<>::instance; + +} // namespace + +typedef asio_execution_execute_fn::impl execute_t; + +template +struct can_execute : + integral_constant::overload != + asio_execution_execute_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_execute_v = can_execute::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace execution +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_EXECUTE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/executor.hpp b/extern/asio-1.18.2/include/asio/execution/executor.hpp new file mode 100644 index 0000000..7e05d5a --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/executor.hpp @@ -0,0 +1,252 @@ +// +// execution/executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_EXECUTOR_HPP +#define ASIO_EXECUTION_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/traits/equality_comparable.hpp" + +#if defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) +# define ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1 +#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct is_executor_of_impl : false_type +{ +}; + +template +struct is_executor_of_impl::type, F>::value + >::type, + typename void_type< + typename result_of::type&()>::type + >::type, + typename enable_if< + is_constructible::type, F>::value + >::type, + typename enable_if< + is_move_constructible::type>::value + >::type, +#if defined(ASIO_HAS_NOEXCEPT) + typename enable_if< + is_nothrow_copy_constructible::value + >::type, + typename enable_if< + is_nothrow_destructible::value + >::type, +#else // defined(ASIO_HAS_NOEXCEPT) + typename enable_if< + is_copy_constructible::value + >::type, + typename enable_if< + is_destructible::value + >::type, +#endif // defined(ASIO_HAS_NOEXCEPT) + typename enable_if< + traits::equality_comparable::is_valid + >::type, + typename enable_if< + traits::equality_comparable::is_noexcept + >::type> : true_type +{ +}; + +template +struct executor_shape +{ + typedef std::size_t type; +}; + +template +struct executor_shape::type> +{ + typedef typename T::shape_type type; +}; + +template +struct executor_index +{ + typedef Default type; +}; + +template +struct executor_index::type> +{ + typedef typename T::index_type type; +}; + +} // namespace detail + +/// The is_executor trait detects whether a type T satisfies the +/// execution::executor concept. +/** + * Class template @c is_executor is a UnaryTypeTrait that is derived from @c + * true_type if the type @c T meets the concept definition for an executor, + * otherwise @c false_type. + */ +template +struct is_executor : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + detail::is_executor_of_impl +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_executor_v = is_executor::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT executor = is_executor::value; + +#define ASIO_EXECUTION_EXECUTOR ::asio::execution::executor + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_EXECUTOR typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +/// The is_executor_of trait detects whether a type T satisfies the +/// execution::executor_of concept for some set of value arguments. +/** + * Class template @c is_executor_of is a type trait that is derived from @c + * true_type if the type @c T meets the concept definition for an executor + * that is invocable with a function object of type @c F, otherwise @c + * false_type. + */ +template +struct is_executor_of : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + integral_constant::value && detail::is_executor_of_impl::value + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_executor_of_v = + is_executor_of::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT executor_of = is_executor_of::value; + +#define ASIO_EXECUTION_EXECUTOR_OF(f) \ + ::asio::execution::executor_of + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_EXECUTOR_OF typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +/// The executor_shape trait detects the type used by an executor to represent +/// the shape of a bulk operation. +/** + * Class template @c executor_shape is a type trait with a nested type alias + * @c type whose type is @c T::shape_type if @c T::shape_type is valid, + * otherwise @c std::size_t. + */ +template +struct executor_shape +#if !defined(GENERATING_DOCUMENTATION) + : detail::executor_shape +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// @c T::shape_type if @c T::shape_type is valid, otherwise @c std::size_t. + typedef automatically_determined type; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template +using executor_shape_t = typename executor_shape::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +/// The executor_index trait detects the type used by an executor to represent +/// an index within a bulk operation. +/** + * Class template @c executor_index is a type trait with a nested type alias + * @c type whose type is @c T::index_type if @c T::index_type is valid, + * otherwise @c executor_shape_t. + */ +template +struct executor_index +#if !defined(GENERATING_DOCUMENTATION) + : detail::executor_index::type> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// @c T::index_type if @c T::index_type is valid, otherwise + /// @c executor_shape_t. + typedef automatically_determined type; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) + +template +using executor_index_t = typename executor_index::type; + +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_EXECUTOR_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/impl/bad_executor.ipp b/extern/asio-1.18.2/include/asio/execution/impl/bad_executor.ipp new file mode 100644 index 0000000..7505e5c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/impl/bad_executor.ipp @@ -0,0 +1,40 @@ +// +// exection/impl/bad_executor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP +#define ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/execution/bad_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +bad_executor::bad_executor() ASIO_NOEXCEPT +{ +} + +const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW +{ + return "bad executor"; +} + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP diff --git a/extern/asio-1.18.2/include/asio/execution/impl/receiver_invocation_error.ipp b/extern/asio-1.18.2/include/asio/execution/impl/receiver_invocation_error.ipp new file mode 100644 index 0000000..5fd4e91 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/impl/receiver_invocation_error.ipp @@ -0,0 +1,36 @@ +// +// exection/impl/receiver_invocation_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP +#define ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/execution/receiver_invocation_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +receiver_invocation_error::receiver_invocation_error() + : std::runtime_error("receiver invocation error") +{ +} + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP diff --git a/extern/asio-1.18.2/include/asio/execution/invocable_archetype.hpp b/extern/asio-1.18.2/include/asio/execution/invocable_archetype.hpp new file mode 100644 index 0000000..b141979 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/invocable_archetype.hpp @@ -0,0 +1,71 @@ +// +// execution/invocable_archetype.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP +#define ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +/// An archetypal function object used for determining adherence to the +/// execution::executor concept. +struct invocable_archetype +{ +#if !defined(GENERATING_DOCUMENTATION) + // Necessary for compatibility with a C++03 implementation of result_of. + typedef void result_type; +#endif // !defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + + /// Function call operator. + template + void operator()(ASIO_MOVE_ARG(Args)...) + { + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + void operator()() + { + } + +#define ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF(n) \ + template \ + void operator()(ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n)) \ + { \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF) +#undef ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) +}; + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + diff --git a/extern/asio-1.18.2/include/asio/execution/mapping.hpp b/extern/asio-1.18.2/include/asio/execution/mapping.hpp new file mode 100644 index 0000000..33924c8 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/mapping.hpp @@ -0,0 +1,1116 @@ +// +// execution/mapping.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_MAPPING_HPP +#define ASIO_EXECUTION_MAPPING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the mapping +/// of execution agents on to threads of execution. +struct mapping_t +{ + /// The mapping_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level mapping_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level mapping_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// A sub-property that indicates that execution agents are mapped on to + /// threads of execution. + struct thread_t + { + /// The mapping_t::thread_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The mapping_t::thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr thread_t(); + + /// Get the value associated with a property object. + /** + * @returns thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that execution agents are mapped on to + /// new threads of execution. + struct new_thread_t + { + /// The mapping_t::new_thread_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The mapping_t::new_thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::new_thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr new_thread_t(); + + /// Get the value associated with a property object. + /** + * @returns new_thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that the mapping of execution agents is + /// implementation-defined. + struct other_t + { + /// The mapping_t::other_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The mapping_t::other_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::other_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr other_t(); + + /// Get the value associated with a property object. + /** + * @returns other_t(); + */ + static constexpr mapping_t value(); + }; + + /// A special value used for accessing the mapping_t::thread_t property. + static constexpr thread_t thread; + + /// A special value used for accessing the mapping_t::new_thread_t property. + static constexpr new_thread_t new_thread; + + /// A special value used for accessing the mapping_t::other_t property. + static constexpr other_t other; + + /// Default constructor. + constexpr mapping_t(); + + /// Construct from a sub-property value. + constexpr mapping_t(thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(new_thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(other_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const mapping_t& a, const mapping_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const mapping_t& a, const mapping_t& b) noexcept; +}; + +/// A special value used for accessing the mapping_t property. +constexpr mapping_t mapping; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace mapping { + +template struct thread_t; +template struct new_thread_t; +template struct other_t; + +} // namespace mapping + +template +struct mapping_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef mapping_t polymorphic_query_result_type; + + typedef detail::mapping::thread_t thread_t; + typedef detail::mapping::new_thread_t new_thread_t; + typedef detail::mapping::other_t other_t; + + ASIO_CONSTEXPR mapping_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR mapping_t(thread_t) + : value_(0) + { + } + + ASIO_CONSTEXPR mapping_t(new_thread_t) + : value_(1) + { + } + + ASIO_CONSTEXPR mapping_t(other_t) + : value_(2) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, mapping_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, mapping_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = mapping_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const mapping_t& a, const mapping_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const mapping_t& a, const mapping_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_mapping_t + { + ASIO_CONSTEXPR convertible_from_mapping_t(mapping_t) {} + }; + + template + friend ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::thread_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, thread_t()); + } + + template + friend ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::new_thread_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, new_thread_t()); + } + + template + friend ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::other_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, other_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const mapping_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T mapping_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const mapping_t mapping_t::instance; +#endif + +template +const typename mapping_t::thread_t mapping_t::thread; + +template +const typename mapping_t::new_thread_t mapping_t::new_thread; + +template +const typename mapping_t::other_t mapping_t::other; + +namespace mapping { + +template +struct thread_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + ASIO_CONSTEXPR thread_t() + { + } + + template + struct query_member : + traits::query_member< + typename mapping_t::template proxy::type, thread_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t::template static_proxy::type, thread_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR thread_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return thread_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = thread_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR mapping_t value() + { + return thread_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const thread_t&, const thread_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const thread_t&, const thread_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T thread_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct new_thread_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + ASIO_CONSTEXPR new_thread_t() + { + } + + template + struct query_member : + traits::query_member< + typename mapping_t::template proxy::type, new_thread_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t::template static_proxy::type, new_thread_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = new_thread_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR mapping_t value() + { + return new_thread_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const new_thread_t&, const new_thread_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const new_thread_t&, const new_thread_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T new_thread_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct other_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + ASIO_CONSTEXPR other_t() + { + } + + template + struct query_member : + traits::query_member< + typename mapping_t::template proxy::type, other_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t::template static_proxy::type, other_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = other_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR mapping_t value() + { + return other_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const other_t&, const other_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const other_t&, const other_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T other_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace mapping +} // namespace detail + +typedef detail::mapping_t<> mapping_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr mapping_t mapping; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const mapping_t& mapping = mapping_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::mapping_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::mapping_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::mapping_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::mapping_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::mapping_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::mapping::thread_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::mapping_t::thread_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::mapping::new_thread_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::mapping::new_thread_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::mapping::other_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::mapping::other_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::thread_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::new_thread_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::other_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_MAPPING_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/occupancy.hpp b/extern/asio-1.18.2/include/asio/execution/occupancy.hpp new file mode 100644 index 0000000..e1842a4 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/occupancy.hpp @@ -0,0 +1,226 @@ +// +// execution/occupancy.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_OCCUPANCY_HPP +#define ASIO_EXECUTION_OCCUPANCY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that gives an estimate of the number of execution agents that +/// should occupy the associated execution context. +struct occupancy_t +{ + /// The occupancy_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The occupancy_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The occupancy_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef std::size_t polymorphic_query_result_type; +}; + +/// A special value used for accessing the occupancy_t property. +constexpr occupancy_t occupancy; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct occupancy_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef std::size_t polymorphic_query_result_type; + + ASIO_CONSTEXPR occupancy_t() + { + } + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, occupancy_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = occupancy_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) + static const occupancy_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T occupancy_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const occupancy_t occupancy_t::instance; +#endif + +} // namespace detail + +typedef detail::occupancy_t<> occupancy_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr occupancy_t occupancy; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const occupancy_t& occupancy = occupancy_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::occupancy_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::occupancy_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_OCCUPANCY_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/operation_state.hpp b/extern/asio-1.18.2/include/asio/execution/operation_state.hpp new file mode 100644 index 0000000..8fb7a94 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/operation_state.hpp @@ -0,0 +1,94 @@ +// +// execution/operation_state.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_OPERATION_STATE_HPP +#define ASIO_EXECUTION_OPERATION_STATE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/start.hpp" + +#if defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) +# define ASIO_HAS_DEDUCED_EXECUTION_IS_OPERATION_STATE_TRAIT 1 +#endif // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct is_operation_state_base : + integral_constant::value + && is_object::value + > +{ +}; + +} // namespace detail + +/// The is_operation_state trait detects whether a type T satisfies the +/// execution::operation_state concept. +/** + * Class template @c is_operation_state is a type trait that is derived from + * @c true_type if the type @c T meets the concept definition for an + * @c operation_state, otherwise @c false_type. + */ +template +struct is_operation_state : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + conditional< + can_start::type>::value + && is_nothrow_start::type>::value, + detail::is_operation_state_base, + false_type + >::type +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_operation_state_v = + is_operation_state::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT operation_state = is_operation_state::value; + +#define ASIO_EXECUTION_OPERATION_STATE \ + ::asio::execution::operation_state + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_OPERATION_STATE typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_OPERATION_STATE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/outstanding_work.hpp b/extern/asio-1.18.2/include/asio/execution/outstanding_work.hpp new file mode 100644 index 0000000..48ed71d --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/outstanding_work.hpp @@ -0,0 +1,867 @@ +// +// execution/outstanding_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_OUTSTANDING_WORK_HPP +#define ASIO_EXECUTION_OUTSTANDING_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether task submission is likely in the future. +struct outstanding_work_t +{ + /// The outstanding_work_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level outstanding_work_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level outstanding_work_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent likely + /// future submission of a function object. + struct untracked_t + { + /// The outstanding_work_t::untracked_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The outstanding_work_t::untracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::untracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr untracked_t(); + + /// Get the value associated with a property object. + /** + * @returns untracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A sub-property that indicates that the executor represents likely + /// future submission of a function object. + struct tracked_t + { + /// The outstanding_work_t::untracked_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The outstanding_work_t::tracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::tracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr tracked_t(); + + /// Get the value associated with a property object. + /** + * @returns tracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A special value used for accessing the outstanding_work_t::untracked_t + /// property. + static constexpr untracked_t untracked; + + /// A special value used for accessing the outstanding_work_t::tracked_t + /// property. + static constexpr tracked_t tracked; + + /// Default constructor. + constexpr outstanding_work_t(); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(untracked_t); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(tracked_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; +}; + +/// A special value used for accessing the outstanding_work_t property. +constexpr outstanding_work_t outstanding_work; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace outstanding_work { + +template struct untracked_t; +template struct tracked_t; + +} // namespace outstanding_work + +template +struct outstanding_work_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef outstanding_work_t polymorphic_query_result_type; + + typedef detail::outstanding_work::untracked_t untracked_t; + typedef detail::outstanding_work::tracked_t tracked_t; + + ASIO_CONSTEXPR outstanding_work_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR outstanding_work_t(untracked_t) + : value_(0) + { + } + + ASIO_CONSTEXPR outstanding_work_t(tracked_t) + : value_(1) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, outstanding_work_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, outstanding_work_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = outstanding_work_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_outstanding_work_t + { + ASIO_CONSTEXPR convertible_from_outstanding_work_t(outstanding_work_t) + { + } + }; + + template + friend ASIO_CONSTEXPR outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::untracked_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, untracked_t()); + } + + template + friend ASIO_CONSTEXPR outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::tracked_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, tracked_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const outstanding_work_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T outstanding_work_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const outstanding_work_t outstanding_work_t::instance; +#endif + +template +const typename outstanding_work_t::untracked_t +outstanding_work_t::untracked; + +template +const typename outstanding_work_t::tracked_t +outstanding_work_t::tracked; + +namespace outstanding_work { + +template +struct untracked_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef outstanding_work_t polymorphic_query_result_type; + + ASIO_CONSTEXPR untracked_t() + { + } + + template + struct query_member : + traits::query_member< + typename outstanding_work_t::template proxy::type, untracked_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename outstanding_work_t::template static_proxy::type, + untracked_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR untracked_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return untracked_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = untracked_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR outstanding_work_t value() + { + return untracked_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const untracked_t&, const untracked_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const untracked_t&, const untracked_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T untracked_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct tracked_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef outstanding_work_t polymorphic_query_result_type; + + ASIO_CONSTEXPR tracked_t() + { + } + + template + struct query_member : + traits::query_member< + typename outstanding_work_t::template proxy::type, tracked_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename outstanding_work_t::template static_proxy::type, + tracked_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = tracked_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR outstanding_work_t value() + { + return tracked_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const tracked_t&, const tracked_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const tracked_t&, const tracked_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T tracked_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace outstanding_work +} // namespace detail + +typedef detail::outstanding_work_t<> outstanding_work_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr outstanding_work_t outstanding_work; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const outstanding_work_t& + outstanding_work = outstanding_work_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::outstanding_work_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::outstanding_work_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::outstanding_work_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::outstanding_work_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::outstanding_work::untracked_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::outstanding_work_t::untracked_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::outstanding_work::tracked_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::outstanding_work::tracked_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::outstanding_work_t::untracked_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::outstanding_work_t::tracked_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_OUTSTANDING_WORK_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/prefer_only.hpp b/extern/asio-1.18.2/include/asio/execution/prefer_only.hpp new file mode 100644 index 0000000..e608a77 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/prefer_only.hpp @@ -0,0 +1,331 @@ +// +// execution/prefer_only.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_PREFER_ONLY_HPP +#define ASIO_EXECUTION_PREFER_ONLY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property adapter that is used with the polymorphic executor wrapper +/// to mark properties as preferable, but not requirable. +template +struct prefer_only +{ + /// The prefer_only adapter applies to the same types as the nested property. + template + static constexpr bool is_applicable_property_v = + is_applicable_property::value; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property can be preferred, it the underlying property can + /// be preferred. + /** + * @c true if @c Property::is_preferable is @c true, otherwise @c false. + */ + static constexpr bool is_preferable = automatically_determined; + + /// The type returned by queries against an @c any_executor. + typedef typename Property::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct prefer_only_is_preferable +{ + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); +}; + +template +struct prefer_only_is_preferable::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); +}; + +template +struct prefer_only_polymorphic_query_result_type +{ +}; + +template +struct prefer_only_polymorphic_query_result_type::type> +{ + typedef typename InnerProperty::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +template +struct prefer_only_property +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } +}; + +#if defined(ASIO_HAS_DECLTYPE) \ + && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template +struct prefer_only_property().value()) + >::type> +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + ASIO_CONSTEXPR auto value() const + ASIO_NOEXCEPT_IF(( + noexcept(asio::declval().value()))) + -> decltype(asio::declval().value()) + { + return property.value(); + } +}; + +#else // defined(ASIO_HAS_DECLTYPE) + // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +struct prefer_only_memfns_base +{ + void value(); +}; + +template +struct prefer_only_memfns_derived + : T, prefer_only_memfns_base +{ +}; + +template +struct prefer_only_memfns_check +{ +}; + +template +char (&prefer_only_value_memfn_helper(...))[2]; + +template +char prefer_only_value_memfn_helper( + prefer_only_memfns_check< + void (prefer_only_memfns_base::*)(), + &prefer_only_memfns_derived::value>*); + +template +struct prefer_only_property(0)) != 1 + && !is_same::value + >::type> +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type + value() const + { + return property.value(); + } +}; + +#endif // defined(ASIO_HAS_DECLTYPE) + // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +} // namespace detail + +template +struct prefer_only : + detail::prefer_only_is_preferable, + detail::prefer_only_polymorphic_query_result_type, + detail::prefer_only_property +{ + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + + ASIO_CONSTEXPR prefer_only(const InnerProperty& p) + : detail::prefer_only_property(p) + { + } + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query() + ASIO_NOEXCEPT_IF(( + traits::static_query::is_noexcept)) + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = prefer_only::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + friend ASIO_CONSTEXPR + typename prefer_result::type + prefer(const Executor& ex, const prefer_only& p, + typename enable_if< + is_same::value + >::type* = 0, + typename enable_if< + can_prefer::value + >::type* = 0) +#if !defined(ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + ASIO_NOEXCEPT_IF(( + is_nothrow_prefer::value)) +#endif // !defined(ASIO_MSVC) + // && !defined(__clang__) + { + return asio::prefer(ex, p.property); + } + + template + friend ASIO_CONSTEXPR + typename query_result::type + query(const Executor& ex, const prefer_only& p, + typename enable_if< + is_same::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(ASIO_MSVC) + // && !defined(__clang__) + { + return asio::query(ex, p.property); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T prefer_only::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace execution + +template +struct is_applicable_property > + : is_applicable_property +{ +}; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query > : + static_query +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free_default, + typename enable_if< + can_prefer::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_prefer::value)); + + typedef typename prefer_result::type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free, + typename enable_if< + can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef typename query_result::type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_PREFER_ONLY_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/receiver.hpp b/extern/asio-1.18.2/include/asio/execution/receiver.hpp new file mode 100644 index 0000000..4f205aa --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/receiver.hpp @@ -0,0 +1,280 @@ +// +// execution/receiver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_RECEIVER_HPP +#define ASIO_EXECUTION_RECEIVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/execution/set_done.hpp" +#include "asio/execution/set_error.hpp" +#include "asio/execution/set_value.hpp" + +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) +# include +#else // defined(ASIO_HAS_STD_EXCEPTION_PTR) +# include "asio/error_code.hpp" +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + +#if defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT) +# define ASIO_HAS_DEDUCED_EXECUTION_IS_RECEIVER_TRAIT 1 +#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) + // && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct is_receiver_base : + integral_constant::type>::value + && is_constructible::type, T>::value + > +{ +}; + +} // namespace detail + +#if defined(ASIO_HAS_STD_EXCEPTION_PTR) +# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT = std::exception_ptr +#else // defined(ASIO_HAS_STD_EXCEPTION_PTR) +# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT \ + = ::asio::error_code +#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR) + +/// The is_receiver trait detects whether a type T satisfies the +/// execution::receiver concept. +/** + * Class template @c is_receiver is a type trait that is derived from @c + * true_type if the type @c T meets the concept definition for a receiver for + * error type @c E, otherwise @c false_type. + */ +template +struct is_receiver : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + conditional< + can_set_done::type>::value + && is_nothrow_set_done::type>::value + && can_set_error::type, E>::value + && is_nothrow_set_error::type, E>::value, + detail::is_receiver_base, + false_type + >::type +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_receiver_v = is_receiver::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT receiver = is_receiver::value; + +#define ASIO_EXECUTION_RECEIVER ::asio::execution::receiver + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_RECEIVER typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// The is_receiver_of trait detects whether a type T satisfies the +/// execution::receiver_of concept for some set of value arguments. +/** + * Class template @c is_receiver_of is a type trait that is derived from @c + * true_type if the type @c T meets the concept definition for a receiver for + * value arguments @c Vs, otherwise @c false_type. + */ +template +struct is_receiver_of : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + conditional< + is_receiver::value, + can_set_value::type, Vs...>, + false_type + >::type +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_receiver_of_v = + is_receiver_of::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT receiver_of = is_receiver_of::value; + +#define ASIO_EXECUTION_RECEIVER_OF_0 \ + ::asio::execution::receiver_of + +#define ASIO_EXECUTION_RECEIVER_OF_1(v) \ + ::asio::execution::receiver_of + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_RECEIVER_OF_0 typename +#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template +struct is_receiver_of; + +template +struct is_receiver_of : + conditional< + is_receiver::value, + can_set_value::type>, + false_type + >::type +{ +}; + +#define ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF(n) \ + template \ + struct is_receiver_of : \ + conditional< \ + conditional, void>::type::value, \ + can_set_value< \ + typename remove_cvref::type, \ + ASIO_VARIADIC_TARGS(n)>, \ + false_type \ + >::type \ + { \ + }; \ + /**/ +ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF) +#undef ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF + +#define ASIO_EXECUTION_RECEIVER_OF_0 typename +#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// The is_nothrow_receiver_of trait detects whether a type T satisfies the +/// execution::receiver_of concept for some set of value arguments, with a +/// noexcept @c set_value operation. +/** + * Class template @c is_nothrow_receiver_of is a type trait that is derived + * from @c true_type if the type @c T meets the concept definition for a + * receiver for value arguments @c Vs, and the expression + * execution::set_value(declval(), declval()...) is noexcept, + * otherwise @c false_type. + */ +template +struct is_nothrow_receiver_of : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + integral_constant::value + && is_nothrow_set_value::type, Vs...>::value + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_nothrow_receiver_of_v = + is_nothrow_receiver_of::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template +struct is_nothrow_receiver_of; + +template +struct is_nothrow_receiver_of : + integral_constant::value + && is_nothrow_set_value::type>::value + > +{ +}; + +#define ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF(n) \ + template \ + struct is_nothrow_receiver_of : \ + integral_constant::value \ + && is_nothrow_set_value::type, \ + ASIO_VARIADIC_TARGS(n)>::value \ + > \ + { \ + }; \ + /**/ +ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF) +#undef ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_RECEIVER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/receiver_invocation_error.hpp b/extern/asio-1.18.2/include/asio/execution/receiver_invocation_error.hpp new file mode 100644 index 0000000..00557da --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/receiver_invocation_error.hpp @@ -0,0 +1,48 @@ +// +// execution/receiver_invocation_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP +#define ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +/// Exception reported via @c set_error when an exception escapes from +/// @c set_value. +class receiver_invocation_error + : public std::runtime_error +#if defined(ASIO_HAS_STD_NESTED_EXCEPTION) + , public std::nested_exception +#endif // defined(ASIO_HAS_STD_NESTED_EXCEPTION) +{ +public: + /// Constructor. + ASIO_DECL receiver_invocation_error(); +}; + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/execution/impl/receiver_invocation_error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/relationship.hpp b/extern/asio-1.18.2/include/asio/execution/relationship.hpp new file mode 100644 index 0000000..95160e0 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/relationship.hpp @@ -0,0 +1,865 @@ +// +// execution/relationship.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_RELATIONSHIP_HPP +#define ASIO_EXECUTION_RELATIONSHIP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/scheduler.hpp" +#include "asio/execution/sender.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether submitted tasks represent continuations of +/// the calling context. +struct relationship_t +{ + /// The relationship_t property applies to executors, senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The top-level relationship_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level relationship_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent a + /// continuation of the calling context. + struct fork_t + { + /// The relationship_t::fork_t property applies to executors, senders, and + /// schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The relationship_t::fork_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::fork_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr fork_t(); + + /// Get the value associated with a property object. + /** + * @returns fork_t(); + */ + static constexpr relationship_t value(); + }; + + /// A sub-property that indicates that the executor represents a continuation + /// of the calling context. + struct continuation_t + { + /// The relationship_t::continuation_t property applies to executors, + /// senders, and schedulers. + template + static constexpr bool is_applicable_property_v = + is_executor_v || is_sender_v || is_scheduler_v; + + /// The relationship_t::continuation_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::continuation_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr continuation_t(); + + /// Get the value associated with a property object. + /** + * @returns continuation_t(); + */ + static constexpr relationship_t value(); + }; + + /// A special value used for accessing the relationship_t::fork_t property. + static constexpr fork_t fork; + + /// A special value used for accessing the relationship_t::continuation_t + /// property. + static constexpr continuation_t continuation; + + /// Default constructor. + constexpr relationship_t(); + + /// Construct from a sub-property value. + constexpr relationship_t(fork_t); + + /// Construct from a sub-property value. + constexpr relationship_t(continuation_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const relationship_t& a, const relationship_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const relationship_t& a, const relationship_t& b) noexcept; +}; + +/// A special value used for accessing the relationship_t property. +constexpr relationship_t relationship; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace relationship { + +template struct fork_t; +template struct continuation_t; + +} // namespace relationship + +template +struct relationship_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef relationship_t polymorphic_query_result_type; + + typedef detail::relationship::fork_t fork_t; + typedef detail::relationship::continuation_t continuation_t; + + ASIO_CONSTEXPR relationship_t() + : value_(-1) + { + } + + ASIO_CONSTEXPR relationship_t(fork_t) + : value_(0) + { + } + + ASIO_CONSTEXPR relationship_t(continuation_t) + : value_(1) + { + } + + template + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template + auto query(ASIO_MOVE_ARG(P) p) const + noexcept( + noexcept( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + declval::type>().query( + ASIO_MOVE_CAST(P)(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template + static constexpr auto query(ASIO_MOVE_ARG(P) p) + noexcept( + noexcept( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + ) + -> decltype( + conditional::type::query(ASIO_MOVE_CAST(P)(p)) + ) + { + return T::query(ASIO_MOVE_CAST(P)(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template + struct query_member : + traits::query_member::type, relationship_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy::type, relationship_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::static_query::is_valid + >::type* = 0, + typename enable_if< + traits::static_query::is_valid + >::type* = 0) ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = relationship_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend ASIO_CONSTEXPR bool operator==( + const relationship_t& a, const relationship_t& b) + { + return a.value_ == b.value_; + } + + friend ASIO_CONSTEXPR bool operator!=( + const relationship_t& a, const relationship_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_relationship_t + { + ASIO_CONSTEXPR convertible_from_relationship_t(relationship_t) + { + } + }; + + template + friend ASIO_CONSTEXPR relationship_t query( + const Executor& ex, convertible_from_relationship_t, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::fork_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, fork_t()); + } + + template + friend ASIO_CONSTEXPR relationship_t query( + const Executor& ex, convertible_from_relationship_t, + typename enable_if< + !can_query::value + >::type* = 0, + typename enable_if< + can_query::value + >::type* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + ASIO_NOEXCEPT_IF(( + is_nothrow_query::continuation_t>::value)) +#else // defined(ASIO_MSVC) + ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, continuation_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation); + +#if !defined(ASIO_HAS_CONSTEXPR) + static const relationship_t instance; +#endif // !defined(ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T relationship_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_CONSTEXPR) +template +const relationship_t relationship_t::instance; +#endif + +template +const typename relationship_t::fork_t +relationship_t::fork; + +template +const typename relationship_t::continuation_t +relationship_t::continuation; + +namespace relationship { + +template +struct fork_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef relationship_t polymorphic_query_result_type; + + ASIO_CONSTEXPR fork_t() + { + } + + template + struct query_member : + traits::query_member< + typename relationship_t::template proxy::type, fork_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename relationship_t::template static_proxy::type, fork_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template + static ASIO_CONSTEXPR fork_t static_query( + typename enable_if< + !query_static_constexpr_member::is_valid + >::type* = 0, + typename enable_if< + !query_member::is_valid + >::type* = 0, + typename enable_if< + !traits::query_free::is_valid + >::type* = 0, + typename enable_if< + !can_query >::value + >::type* = 0) ASIO_NOEXCEPT + { + return fork_t(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = fork_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR relationship_t value() + { + return fork_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const fork_t&, const fork_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const fork_t&, const fork_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T fork_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct continuation_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template + ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = ( + is_executor::value + || conditional< + is_executor::value, + false_type, + is_sender + >::type::value + || conditional< + is_executor::value, + false_type, + is_scheduler + >::type::value)); +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef relationship_t polymorphic_query_result_type; + + ASIO_CONSTEXPR continuation_t() + { + } + + template + struct query_member : + traits::query_member< + typename relationship_t::template proxy::type, continuation_t> {}; + + template + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename relationship_t::template static_proxy::type, + continuation_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static ASIO_CONSTEXPR + typename query_static_constexpr_member::result_type + static_query() + ASIO_NOEXCEPT_IF(( + query_static_constexpr_member::is_noexcept)) + { + return query_static_constexpr_member::value(); + } + + template ())> + static ASIO_CONSTEXPR const T static_query_v + = continuation_t::static_query(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static ASIO_CONSTEXPR relationship_t value() + { + return continuation_t(); + } + + friend ASIO_CONSTEXPR bool operator==( + const continuation_t&, const continuation_t&) + { + return true; + } + + friend ASIO_CONSTEXPR bool operator!=( + const continuation_t&, const continuation_t&) + { + return false; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T continuation_t::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace relationship +} // namespace detail + +typedef detail::relationship_t<> relationship_t; + +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr relationship_t relationship; +#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const relationship_t& + relationship = relationship_t::instance; } +#endif + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +template +struct is_applicable_property + : integral_constant::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_sender + >::type::value + || conditional< + execution::is_executor::value, + false_type, + execution::is_scheduler + >::type::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::relationship_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::relationship_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::relationship_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::relationship_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::relationship_t<0>:: + query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::relationship_t<0>:: + query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member::value(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + && !execution::detail::relationship::fork_t<0>:: + query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::relationship_t::fork_t result_type; + + static ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query:: + query_static_constexpr_member::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename execution::detail::relationship::continuation_t<0>:: + query_static_constexpr_member::result_type result_type; + + static ASIO_CONSTEXPR result_type value() + { + return execution::detail::relationship::continuation_t<0>:: + query_static_constexpr_member::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::relationship_t::fork_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::relationship_t::continuation_t>::value)); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_RELATIONSHIP_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/schedule.hpp b/extern/asio-1.18.2/include/asio/execution/schedule.hpp new file mode 100644 index 0000000..fde0cdd --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/schedule.hpp @@ -0,0 +1,287 @@ +// +// execution/schedule.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_SCHEDULE_HPP +#define ASIO_EXECUTION_SCHEDULE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/traits/schedule_member.hpp" +#include "asio/traits/schedule_free.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { +namespace execution { + +/// A customisation point that is used to obtain a sender from a scheduler. +/** + * The name execution::schedule denotes a customisation point object. + * For some subexpression s, let S be a type such that + * decltype((s)) is S. The expression + * execution::schedule(s) is expression-equivalent to: + * + * @li s.schedule(), if that expression is valid and its type models + * sender. + * + * @li Otherwise, schedule(s), if that expression is valid and its + * type models sender with overload resolution performed in a context + * that includes the declaration void schedule(); and that does not + * include a declaration of execution::schedule. + * + * @li Otherwise, S if S satisfies executor. + * + * @li Otherwise, execution::schedule(s) is ill-formed. + */ +inline constexpr unspecified schedule = unspecified; + +/// A type trait that determines whether a @c schedule expression is +/// well-formed. +/** + * Class template @c can_schedule is a trait that is derived from @c true_type + * if the expression execution::schedule(std::declval()) is well + * formed; otherwise @c false_type. + */ +template +struct can_schedule : + integral_constant +{ +}; + +} // namespace execution +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_execution_schedule_fn { + +using asio::decay; +using asio::declval; +using asio::enable_if; +using asio::execution::is_executor; +using asio::traits::schedule_free; +using asio::traits::schedule_member; + +void schedule(); + +enum overload_type +{ + identity, + call_member, + call_free, + ill_formed +}; + +template +struct call_traits +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::is_valid + >::type> : + schedule_member +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::is_valid + >::type, + typename enable_if< + schedule_free::is_valid + >::type> : + schedule_free +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +template +struct call_traits::is_valid + >::type, + typename enable_if< + !schedule_free::is_valid + >::type, + typename enable_if< + is_executor::type>::value + >::type> +{ + ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + +#if defined(ASIO_HAS_MOVE) + typedef ASIO_MOVE_ARG(S) result_type; +#else // defined(ASIO_HAS_MOVE) + typedef ASIO_MOVE_ARG(typename decay::type) result_type; +#endif // defined(ASIO_HAS_MOVE) +}; + +struct impl +{ + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == identity, + typename call_traits::result_type + >::type + operator()(ASIO_MOVE_ARG(S) s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return ASIO_MOVE_CAST(S)(s); + } + +#if defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S&& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return ASIO_MOVE_CAST(S)(s).schedule(); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S&& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return schedule(ASIO_MOVE_CAST(S)(s)); + } +#else // defined(ASIO_HAS_MOVE) + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(S& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.schedule(); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()(const S& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return s.schedule(); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(S& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return schedule(s); + } + + template + ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()(const S& s) const + ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return schedule(s); + } +#endif // defined(ASIO_HAS_MOVE) +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_execution_schedule_fn +namespace asio { +namespace execution { +namespace { + +static ASIO_CONSTEXPR const asio_execution_schedule_fn::impl& + schedule = asio_execution_schedule_fn::static_instance<>::instance; + +} // namespace + +template +struct can_schedule : + integral_constant::overload != + asio_execution_schedule_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_schedule_v = can_schedule::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_nothrow_schedule : + integral_constant::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_schedule_v + = is_nothrow_schedule::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace execution +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_SCHEDULE_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/scheduler.hpp b/extern/asio-1.18.2/include/asio/execution/scheduler.hpp new file mode 100644 index 0000000..b99ab3c --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/scheduler.hpp @@ -0,0 +1,86 @@ +// +// execution/scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_SCHEDULER_HPP +#define ASIO_EXECUTION_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/schedule.hpp" +#include "asio/traits/equality_comparable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template +struct is_scheduler_base : + integral_constant::type>::value + && traits::equality_comparable::type>::is_valid + > +{ +}; + +} // namespace detail + +/// The is_scheduler trait detects whether a type T satisfies the +/// execution::scheduler concept. +/** + * Class template @c is_scheduler is a type trait that is derived from @c + * true_type if the type @c T meets the concept definition for a scheduler for + * error type @c E, otherwise @c false_type. + */ +template +struct is_scheduler : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + conditional< + can_schedule::value, + detail::is_scheduler_base, + false_type + >::type +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template +ASIO_CONSTEXPR const bool is_scheduler_v = is_scheduler::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template +ASIO_CONCEPT scheduler = is_scheduler::value; + +#define ASIO_EXECUTION_SCHEDULER ::asio::execution::scheduler + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_SCHEDULER typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_SCHEDULER_HPP diff --git a/extern/asio-1.18.2/include/asio/execution/sender.hpp b/extern/asio-1.18.2/include/asio/execution/sender.hpp new file mode 100644 index 0000000..4e4ba47 --- /dev/null +++ b/extern/asio-1.18.2/include/asio/execution/sender.hpp @@ -0,0 +1,311 @@ +// +// execution/sender.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2021 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 ASIO_EXECUTION_SENDER_HPP +#define ASIO_EXECUTION_SENDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/detail/as_invocable.hpp" +#include "asio/execution/detail/void_receiver.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/receiver.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(ASIO_HAS_ALIAS_TEMPLATES) \ + && defined(ASIO_HAS_VARIADIC_TEMPLATES) \ + && defined(ASIO_HAS_DECLTYPE) \ + && !defined(ASIO_MSVC) || (_MSC_VER >= 1910) +# define ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT 1 +#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) + // && defined(ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(ASIO_HAS_DECLTYPE) + // && !defined(ASIO_MSVC) || (_MSC_VER >= 1910) + +namespace asio { +namespace execution { +namespace detail { + +namespace sender_base_ns { struct sender_base {}; } + +template +struct sender_traits_base +{ + typedef void asio_execution_sender_traits_base_is_unspecialised; +}; + +template +struct sender_traits_base::value + >::type> +{ +}; + +template +struct has_sender_types : false_type +{ +}; + +#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) + +template < + template < + template class Tuple, + template class Variant + > class> +struct has_value_types +{ + typedef void type; +}; + +template < + template < + template class Variant + > class> +struct has_error_types +{ + typedef void type; +}; + +template +struct has_sender_types::type, + typename has_error_types::type, + typename conditional::type> : true_type +{ +}; + +template +struct sender_traits_base::value + >::type> +{ + template < + template class Tuple, + template class Variant> + using value_types = typename S::template value_types; + + template